sequel 3.21.0 → 3.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. data/CHANGELOG +855 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +23 -7
  4. data/Rakefile +42 -24
  5. data/bin/sequel +26 -8
  6. data/doc/active_record.rdoc +1 -0
  7. data/doc/advanced_associations.rdoc +171 -11
  8. data/doc/association_basics.rdoc +293 -43
  9. data/doc/dataset_basics.rdoc +5 -5
  10. data/doc/dataset_filtering.rdoc +8 -0
  11. data/doc/mass_assignment.rdoc +56 -0
  12. data/doc/migration.rdoc +85 -552
  13. data/doc/model_hooks.rdoc +78 -27
  14. data/doc/object_model.rdoc +541 -0
  15. data/doc/opening_databases.rdoc +97 -50
  16. data/doc/prepared_statements.rdoc +40 -14
  17. data/doc/querying.rdoc +28 -4
  18. data/doc/reflection.rdoc +30 -4
  19. data/doc/release_notes/3.22.0.txt +39 -0
  20. data/doc/release_notes/3.23.0.txt +172 -0
  21. data/doc/release_notes/3.24.0.txt +420 -0
  22. data/doc/release_notes/3.25.0.txt +88 -0
  23. data/doc/release_notes/3.26.0.txt +88 -0
  24. data/doc/release_notes/3.27.0.txt +82 -0
  25. data/doc/release_notes/3.28.0.txt +304 -0
  26. data/doc/release_notes/3.29.0.txt +459 -0
  27. data/doc/release_notes/3.30.0.txt +135 -0
  28. data/doc/release_notes/3.31.0.txt +146 -0
  29. data/doc/release_notes/3.32.0.txt +202 -0
  30. data/doc/release_notes/3.33.0.txt +157 -0
  31. data/doc/release_notes/3.34.0.txt +671 -0
  32. data/doc/release_notes/3.35.0.txt +144 -0
  33. data/doc/release_notes/3.36.0.txt +245 -0
  34. data/doc/schema_modification.rdoc +572 -0
  35. data/doc/sharding.rdoc +95 -3
  36. data/doc/testing.rdoc +129 -0
  37. data/doc/thread_safety.rdoc +17 -0
  38. data/doc/transactions.rdoc +137 -0
  39. data/doc/virtual_rows.rdoc +51 -2
  40. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  41. data/lib/sequel/adapters/ado.rb +40 -18
  42. data/lib/sequel/adapters/amalgalite.rb +17 -9
  43. data/lib/sequel/adapters/db2.rb +175 -86
  44. data/lib/sequel/adapters/dbi.rb +15 -15
  45. data/lib/sequel/adapters/do/mysql.rb +17 -11
  46. data/lib/sequel/adapters/do/postgres.rb +1 -57
  47. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  48. data/lib/sequel/adapters/do.rb +18 -36
  49. data/lib/sequel/adapters/firebird.rb +27 -208
  50. data/lib/sequel/adapters/ibmdb.rb +453 -0
  51. data/lib/sequel/adapters/informix.rb +6 -23
  52. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  53. data/lib/sequel/adapters/jdbc/db2.rb +47 -0
  54. data/lib/sequel/adapters/jdbc/derby.rb +287 -0
  55. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  56. data/lib/sequel/adapters/jdbc/h2.rb +73 -31
  57. data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
  58. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  59. data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
  60. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  61. data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
  62. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  63. data/lib/sequel/adapters/jdbc/postgresql.rb +58 -48
  64. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  65. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  66. data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
  67. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  68. data/lib/sequel/adapters/jdbc.rb +265 -94
  69. data/lib/sequel/adapters/mock.rb +361 -0
  70. data/lib/sequel/adapters/mysql.rb +118 -222
  71. data/lib/sequel/adapters/mysql2.rb +58 -57
  72. data/lib/sequel/adapters/odbc/mssql.rb +15 -7
  73. data/lib/sequel/adapters/odbc.rb +28 -9
  74. data/lib/sequel/adapters/openbase.rb +3 -5
  75. data/lib/sequel/adapters/oracle.rb +349 -53
  76. data/lib/sequel/adapters/postgres.rb +356 -107
  77. data/lib/sequel/adapters/shared/access.rb +32 -9
  78. data/lib/sequel/adapters/shared/db2.rb +342 -0
  79. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  80. data/lib/sequel/adapters/shared/informix.rb +53 -0
  81. data/lib/sequel/adapters/shared/mssql.rb +335 -118
  82. data/lib/sequel/adapters/shared/mysql.rb +340 -76
  83. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
  84. data/lib/sequel/adapters/shared/oracle.rb +243 -45
  85. data/lib/sequel/adapters/shared/postgres.rb +524 -279
  86. data/lib/sequel/adapters/shared/progress.rb +5 -8
  87. data/lib/sequel/adapters/shared/sqlite.rb +265 -89
  88. data/lib/sequel/adapters/sqlite.rb +101 -39
  89. data/lib/sequel/adapters/swift/mysql.rb +9 -12
  90. data/lib/sequel/adapters/swift/postgres.rb +9 -74
  91. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  92. data/lib/sequel/adapters/swift.rb +8 -7
  93. data/lib/sequel/adapters/tinytds.rb +161 -21
  94. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  95. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  96. data/lib/sequel/ast_transformer.rb +194 -0
  97. data/lib/sequel/connection_pool/sharded_single.rb +11 -1
  98. data/lib/sequel/connection_pool/sharded_threaded.rb +28 -2
  99. data/lib/sequel/connection_pool/single.rb +5 -0
  100. data/lib/sequel/connection_pool/threaded.rb +38 -14
  101. data/lib/sequel/connection_pool.rb +10 -2
  102. data/lib/sequel/core.rb +118 -11
  103. data/lib/sequel/database/connecting.rb +38 -28
  104. data/lib/sequel/database/dataset.rb +4 -4
  105. data/lib/sequel/database/dataset_defaults.rb +63 -2
  106. data/lib/sequel/database/logging.rb +7 -2
  107. data/lib/sequel/database/misc.rb +150 -46
  108. data/lib/sequel/database/query.rb +215 -65
  109. data/lib/sequel/database/schema_generator.rb +64 -20
  110. data/lib/sequel/database/schema_methods.rb +212 -54
  111. data/lib/sequel/dataset/actions.rb +322 -85
  112. data/lib/sequel/dataset/features.rb +96 -8
  113. data/lib/sequel/dataset/graph.rb +38 -11
  114. data/lib/sequel/dataset/misc.rb +50 -23
  115. data/lib/sequel/dataset/mutation.rb +12 -7
  116. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  117. data/lib/sequel/dataset/query.rb +237 -44
  118. data/lib/sequel/dataset/sql.rb +698 -278
  119. data/lib/sequel/dataset.rb +8 -0
  120. data/lib/sequel/exceptions.rb +4 -0
  121. data/lib/sequel/extensions/_pretty_table.rb +79 -0
  122. data/lib/sequel/extensions/arbitrary_servers.rb +108 -0
  123. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  124. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +16 -34
  125. data/lib/sequel/extensions/migration.rb +97 -11
  126. data/lib/sequel/extensions/named_timezones.rb +5 -0
  127. data/lib/sequel/extensions/null_dataset.rb +90 -0
  128. data/lib/sequel/extensions/pg_array.rb +460 -0
  129. data/lib/sequel/extensions/pg_array_ops.rb +220 -0
  130. data/lib/sequel/extensions/pg_auto_parameterize.rb +169 -0
  131. data/lib/sequel/extensions/pg_hstore.rb +296 -0
  132. data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
  133. data/lib/sequel/extensions/pg_inet.rb +89 -0
  134. data/lib/sequel/extensions/pg_json.rb +178 -0
  135. data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
  136. data/lib/sequel/extensions/pretty_table.rb +5 -71
  137. data/lib/sequel/extensions/query.rb +1 -1
  138. data/lib/sequel/extensions/query_literals.rb +79 -0
  139. data/lib/sequel/extensions/schema_caching.rb +76 -0
  140. data/lib/sequel/extensions/schema_dumper.rb +251 -37
  141. data/lib/sequel/extensions/select_remove.rb +35 -0
  142. data/lib/sequel/extensions/server_block.rb +139 -0
  143. data/lib/sequel/extensions/sql_expr.rb +4 -110
  144. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  145. data/lib/sequel/extensions/to_dot.rb +95 -83
  146. data/lib/sequel/model/associations.rb +1187 -393
  147. data/lib/sequel/model/base.rb +578 -170
  148. data/lib/sequel/model/errors.rb +1 -1
  149. data/lib/sequel/model/exceptions.rb +5 -1
  150. data/lib/sequel/model/inflections.rb +1 -1
  151. data/lib/sequel/model.rb +30 -11
  152. data/lib/sequel/no_core_ext.rb +2 -0
  153. data/lib/sequel/plugins/active_model.rb +13 -1
  154. data/lib/sequel/plugins/association_pks.rb +22 -4
  155. data/lib/sequel/plugins/caching.rb +25 -18
  156. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  157. data/lib/sequel/plugins/composition.rb +44 -12
  158. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  159. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  160. data/lib/sequel/plugins/dirty.rb +214 -0
  161. data/lib/sequel/plugins/eager_each.rb +59 -0
  162. data/lib/sequel/plugins/force_encoding.rb +6 -6
  163. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  164. data/lib/sequel/plugins/identity_map.rb +123 -8
  165. data/lib/sequel/plugins/instance_filters.rb +10 -0
  166. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  167. data/lib/sequel/plugins/json_serializer.rb +58 -6
  168. data/lib/sequel/plugins/list.rb +12 -2
  169. data/lib/sequel/plugins/many_through_many.rb +79 -28
  170. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  171. data/lib/sequel/plugins/nested_attributes.rb +139 -63
  172. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  173. data/lib/sequel/plugins/prepared_statements.rb +167 -0
  174. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  175. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  176. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  177. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  178. data/lib/sequel/plugins/schema.rb +7 -2
  179. data/lib/sequel/plugins/serialization.rb +98 -49
  180. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  181. data/lib/sequel/plugins/sharding.rb +21 -54
  182. data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
  183. data/lib/sequel/plugins/static_cache.rb +99 -0
  184. data/lib/sequel/plugins/subclasses.rb +10 -2
  185. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  186. data/lib/sequel/plugins/timestamps.rb +1 -1
  187. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  188. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  189. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  190. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  191. data/lib/sequel/sql.rb +526 -59
  192. data/lib/sequel/timezones.rb +57 -38
  193. data/lib/sequel/version.rb +1 -1
  194. data/spec/adapters/db2_spec.rb +146 -0
  195. data/spec/adapters/firebird_spec.rb +1 -1
  196. data/spec/adapters/mssql_spec.rb +142 -40
  197. data/spec/adapters/mysql_spec.rb +380 -234
  198. data/spec/adapters/oracle_spec.rb +67 -77
  199. data/spec/adapters/postgres_spec.rb +1050 -212
  200. data/spec/adapters/spec_helper.rb +8 -5
  201. data/spec/adapters/sqlite_spec.rb +139 -27
  202. data/spec/core/connection_pool_spec.rb +196 -93
  203. data/spec/core/database_spec.rb +879 -510
  204. data/spec/core/dataset_spec.rb +1415 -1086
  205. data/spec/core/expression_filters_spec.rb +554 -109
  206. data/spec/core/mock_adapter_spec.rb +449 -0
  207. data/spec/core/object_graph_spec.rb +86 -114
  208. data/spec/core/schema_generator_spec.rb +4 -4
  209. data/spec/core/schema_spec.rb +482 -38
  210. data/spec/core/spec_helper.rb +6 -48
  211. data/spec/extensions/active_model_spec.rb +13 -0
  212. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  213. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  214. data/spec/extensions/association_dependencies_spec.rb +15 -25
  215. data/spec/extensions/association_pks_spec.rb +66 -32
  216. data/spec/extensions/association_proxies_spec.rb +4 -4
  217. data/spec/extensions/caching_spec.rb +47 -51
  218. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  219. data/spec/extensions/columns_introspection_spec.rb +91 -0
  220. data/spec/extensions/composition_spec.rb +18 -13
  221. data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +119 -139
  222. data/spec/extensions/dataset_associations_spec.rb +199 -0
  223. data/spec/extensions/defaults_setter_spec.rb +64 -0
  224. data/spec/extensions/dirty_spec.rb +155 -0
  225. data/spec/extensions/eager_each_spec.rb +34 -0
  226. data/spec/extensions/force_encoding_spec.rb +4 -2
  227. data/spec/extensions/hook_class_methods_spec.rb +69 -92
  228. data/spec/extensions/identity_map_spec.rb +131 -22
  229. data/spec/extensions/inflector_spec.rb +0 -4
  230. data/spec/extensions/instance_filters_spec.rb +11 -21
  231. data/spec/extensions/instance_hooks_spec.rb +72 -0
  232. data/spec/extensions/json_serializer_spec.rb +49 -6
  233. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  234. data/spec/extensions/list_spec.rb +48 -39
  235. data/spec/extensions/many_through_many_spec.rb +283 -250
  236. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  237. data/spec/extensions/migration_spec.rb +140 -35
  238. data/spec/extensions/named_timezones_spec.rb +29 -11
  239. data/spec/extensions/nested_attributes_spec.rb +251 -89
  240. data/spec/extensions/null_dataset_spec.rb +85 -0
  241. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  242. data/spec/extensions/pg_array_ops_spec.rb +105 -0
  243. data/spec/extensions/pg_array_spec.rb +196 -0
  244. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  245. data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
  246. data/spec/extensions/pg_hstore_spec.rb +195 -0
  247. data/spec/extensions/pg_inet_spec.rb +44 -0
  248. data/spec/extensions/pg_json_spec.rb +101 -0
  249. data/spec/extensions/pg_statement_cache_spec.rb +209 -0
  250. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  251. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  252. data/spec/extensions/prepared_statements_spec.rb +87 -0
  253. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  254. data/spec/extensions/pretty_table_spec.rb +7 -6
  255. data/spec/extensions/query_literals_spec.rb +168 -0
  256. data/spec/extensions/query_spec.rb +6 -0
  257. data/spec/extensions/rcte_tree_spec.rb +50 -43
  258. data/spec/extensions/schema_caching_spec.rb +41 -0
  259. data/spec/extensions/schema_dumper_spec.rb +429 -22
  260. data/spec/extensions/schema_spec.rb +25 -21
  261. data/spec/extensions/select_remove_spec.rb +38 -0
  262. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  263. data/spec/extensions/serialization_spec.rb +85 -43
  264. data/spec/extensions/server_block_spec.rb +90 -0
  265. data/spec/extensions/sharding_spec.rb +69 -143
  266. data/spec/extensions/single_table_inheritance_spec.rb +23 -29
  267. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  268. data/spec/extensions/spec_helper.rb +22 -61
  269. data/spec/extensions/sql_expr_spec.rb +29 -60
  270. data/spec/extensions/static_cache_spec.rb +145 -0
  271. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  272. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  273. data/spec/extensions/timestamps_spec.rb +6 -6
  274. data/spec/extensions/to_dot_spec.rb +4 -7
  275. data/spec/extensions/touch_spec.rb +13 -14
  276. data/spec/extensions/tree_spec.rb +11 -26
  277. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  278. data/spec/extensions/update_primary_key_spec.rb +30 -24
  279. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  280. data/spec/extensions/validation_helpers_spec.rb +16 -35
  281. data/spec/extensions/xml_serializer_spec.rb +29 -4
  282. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  283. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  284. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  285. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  286. data/spec/integration/associations_test.rb +659 -21
  287. data/spec/integration/database_test.rb +9 -3
  288. data/spec/integration/dataset_test.rb +605 -91
  289. data/spec/integration/eager_loader_test.rb +19 -21
  290. data/spec/integration/migrator_test.rb +2 -3
  291. data/spec/integration/model_test.rb +81 -2
  292. data/spec/integration/plugin_test.rb +454 -143
  293. data/spec/integration/prepared_statement_test.rb +263 -128
  294. data/spec/integration/schema_test.rb +309 -43
  295. data/spec/integration/spec_helper.rb +40 -30
  296. data/spec/integration/timezone_test.rb +38 -12
  297. data/spec/integration/transaction_test.rb +183 -8
  298. data/spec/integration/type_test.rb +18 -4
  299. data/spec/model/association_reflection_spec.rb +201 -7
  300. data/spec/model/associations_spec.rb +1067 -661
  301. data/spec/model/base_spec.rb +329 -95
  302. data/spec/model/dataset_methods_spec.rb +7 -27
  303. data/spec/model/eager_loading_spec.rb +677 -676
  304. data/spec/model/hooks_spec.rb +349 -67
  305. data/spec/model/model_spec.rb +240 -168
  306. data/spec/model/plugins_spec.rb +24 -13
  307. data/spec/model/record_spec.rb +490 -232
  308. data/spec/model/spec_helper.rb +14 -71
  309. data/spec/model/validations_spec.rb +11 -0
  310. data/spec/rcov.opts +2 -0
  311. metadata +178 -80
@@ -5,97 +5,70 @@ rescue LoadError
5
5
  end
6
6
  raise(LoadError, "require 'mysql' did not define Mysql::CLIENT_MULTI_RESULTS!\n You are probably using the pure ruby mysql.rb driver,\n which Sequel does not support. You need to install\n the C based adapter, and make sure that the mysql.so\n file is loaded instead of the mysql.rb file.\n") unless defined?(Mysql::CLIENT_MULTI_RESULTS)
7
7
 
8
- Sequel.require %w'shared/mysql utils/stored_procedures', 'adapters'
8
+ Sequel.require %w'shared/mysql_prepared_statements', 'adapters'
9
9
 
10
10
  module Sequel
11
11
  # Module for holding all MySQL-related classes and modules for Sequel.
12
12
  module MySQL
13
13
  TYPE_TRANSLATOR = tt = Class.new do
14
14
  def boolean(s) s.to_i != 0 end
15
- def blob(s) ::Sequel::SQL::Blob.new(s) end
16
15
  def integer(s) s.to_i end
17
16
  def float(s) s.to_f end
18
- def decimal(s) ::BigDecimal.new(s) end
19
- def date(s) ::Sequel.string_to_date(s) end
20
- def time(s) ::Sequel.string_to_time(s) end
21
- def timestamp(s) ::Sequel.database_to_application_timestamp(s) end
22
- def date_conv(s) ::Sequel::MySQL.convert_date_time(:string_to_date, s) end
23
- def time_conv(s) ::Sequel::MySQL.convert_date_time(:string_to_time, s) end
24
- def timestamp_conv(s) ::Sequel::MySQL.convert_date_time(:database_to_application_timestamp, s) end
25
17
  end.new
26
18
 
27
19
  # Hash with integer keys and callable values for converting MySQL types.
28
20
  MYSQL_TYPES = {}
29
21
  {
30
- [0, 246] => tt.method(:decimal),
31
- [2, 3, 8, 9, 13, 247, 248] => tt.method(:integer),
32
- [4, 5] => tt.method(:float),
33
- [249, 250, 251, 252] => tt.method(:blob)
22
+ [0, 246] => ::BigDecimal.method(:new),
23
+ [2, 3, 8, 9, 13, 247, 248] => tt.method(:integer),
24
+ [4, 5] => tt.method(:float),
25
+ [249, 250, 251, 252] => ::Sequel::SQL::Blob.method(:new)
34
26
  }.each do |k,v|
35
27
  k.each{|n| MYSQL_TYPES[n] = v}
36
28
  end
37
29
 
38
- # Modify the type translator used for the tinyint type based
39
- # on the value given.
40
- def self.convert_tinyint_to_bool=(v)
41
- MYSQL_TYPES[1] = TYPE_TRANSLATOR.method(v ? :boolean : :integer)
42
- @convert_tinyint_to_bool = v
43
- end
44
- self.convert_tinyint_to_bool = convert_tinyint_to_bool
45
-
46
30
  class << self
47
- # By default, Sequel raises an exception if in invalid date or time is used.
48
- # However, if this is set to nil or :nil, the adapter treats dates
49
- # like 0000-00-00 and times like 838:00:00 as nil values. If set to :string,
50
- # it returns the strings as is.
51
- attr_reader :convert_invalid_date_time
52
- end
53
-
54
- # Modify the type translators for the date, time, and timestamp types
55
- # depending on the value given.
56
- def self.convert_invalid_date_time=(v)
57
- MYSQL_TYPES[11] = TYPE_TRANSLATOR.method(v == false ? :time : :time_conv)
58
- m = TYPE_TRANSLATOR.method(v == false ? :date : :date_conv)
59
- [10, 14].each{|i| MYSQL_TYPES[i] = m}
60
- m = TYPE_TRANSLATOR.method(v == false ? :timestamp : :timestamp_conv)
61
- [7, 12].each{|i| MYSQL_TYPES[i] = m}
62
- @convert_invalid_date_time = v
31
+ # Whether to convert invalid date time values by default.
32
+ #
33
+ # Only applies to Sequel::Database instances created after this
34
+ # has been set.
35
+ attr_accessor :convert_invalid_date_time
63
36
  end
64
37
  self.convert_invalid_date_time = false
65
38
 
66
- # If convert_invalid_date_time is nil, :nil, or :string and
67
- # the conversion raises an InvalidValue exception, return v
68
- # if :string and nil otherwise.
69
- def self.convert_date_time(meth, v)
70
- begin
71
- Sequel.send(meth, v)
72
- rescue InvalidValue
73
- case @convert_invalid_date_time
74
- when nil, :nil
75
- nil
76
- when :string
77
- v
78
- else
79
- raise
80
- end
81
- end
82
- end
83
-
84
39
  # Database class for MySQL databases used with Sequel.
85
40
  class Database < Sequel::Database
86
41
  include Sequel::MySQL::DatabaseMethods
42
+ include Sequel::MySQL::PreparedStatements::DatabaseMethods
87
43
 
88
44
  # Mysql::Error messages that indicate the current connection should be disconnected
89
45
  MYSQL_DATABASE_DISCONNECT_ERRORS = /\A(Commands out of sync; you can't run this command now|Can't connect to local MySQL server through socket|MySQL server has gone away|Lost connection to MySQL server during query)/
46
+
47
+ # Regular expression used for getting accurate number of rows
48
+ # matched by an update statement.
49
+ AFFECTED_ROWS_RE = /Rows matched:\s+(\d+)\s+Changed:\s+\d+\s+Warnings:\s+\d+/.freeze
90
50
 
91
51
  set_adapter_scheme :mysql
52
+
53
+ # Hash of conversion procs for the current database
54
+ attr_reader :conversion_procs
55
+ #
56
+ # Whether to convert tinyint columns to bool for the current database
57
+ attr_reader :convert_tinyint_to_bool
58
+
59
+ # By default, Sequel raises an exception if in invalid date or time is used.
60
+ # However, if this is set to nil or :nil, the adapter treats dates
61
+ # like 0000-00-00 and times like 838:00:00 as nil values. If set to :string,
62
+ # it returns the strings as is.
63
+ attr_reader :convert_invalid_date_time
92
64
 
93
- # Support stored procedures on MySQL
94
- def call_sproc(name, opts={}, &block)
95
- args = opts[:args] || []
96
- execute("CALL #{name}#{args.empty? ? '()' : literal(args)}", opts.merge(:sproc=>false), &block)
65
+ def initialize(opts={})
66
+ super
67
+ @conversion_procs = MYSQL_TYPES.dup
68
+ self.convert_tinyint_to_bool = Sequel::MySQL.convert_tinyint_to_bool
69
+ self.convert_invalid_date_time = Sequel::MySQL.convert_invalid_date_time
97
70
  end
98
-
71
+
99
72
  # Connect to the database. In addition to the usual database options,
100
73
  # the following options have effect:
101
74
  #
@@ -139,52 +112,57 @@ module Sequel
139
112
  opts[:user],
140
113
  opts[:password],
141
114
  opts[:database],
142
- opts[:port],
115
+ (opts[:port].to_i if opts[:port]),
143
116
  opts[:socket],
144
117
  Mysql::CLIENT_MULTI_RESULTS +
145
118
  Mysql::CLIENT_MULTI_STATEMENTS +
146
119
  (opts[:compress] == false ? 0 : Mysql::CLIENT_COMPRESS)
147
120
  )
148
- sqls = []
121
+ sqls = mysql_connection_setting_sqls
122
+
149
123
  # Set encoding a slightly different way after connecting,
150
124
  # in case the READ_DEFAULT_GROUP overrode the provided encoding.
151
125
  # Doesn't work across implicit reconnects, but Sequel doesn't turn on
152
126
  # that feature.
153
- sqls << "SET NAMES #{literal(encoding.to_s)}" if encoding
154
-
155
- # Increase timeout so mysql server doesn't disconnect us
156
- # Value used by default is maximum allowed value on Windows.
157
- sqls << "SET @@wait_timeout = #{opts[:timeout] || 2147483}"
158
-
159
- # By default, MySQL 'where id is null' selects the last inserted id
160
- sqls << "SET SQL_AUTO_IS_NULL=0" unless opts[:auto_is_null]
127
+ sqls.unshift("SET NAMES #{literal(encoding.to_s)}") if encoding
161
128
 
162
129
  sqls.each{|sql| log_yield(sql){conn.query(sql)}}
163
130
 
164
- class << conn
165
- attr_accessor :prepared_statements
166
- end
167
- conn.prepared_statements = {}
131
+ add_prepared_statements_cache(conn)
168
132
  conn
169
133
  end
170
134
 
171
- # Returns instance of Sequel::MySQL::Dataset with the given options.
172
- def dataset(opts = nil)
173
- MySQL::Dataset.new(self, opts)
135
+ # Modify the type translators for the date, time, and timestamp types
136
+ # depending on the value given.
137
+ def convert_invalid_date_time=(v)
138
+ m0 = ::Sequel.method(:string_to_time)
139
+ @conversion_procs[11] = (v != false) ? lambda{|v| convert_date_time(v, &m0)} : m0
140
+ m1 = ::Sequel.method(:string_to_date)
141
+ m = (v != false) ? lambda{|v| convert_date_time(v, &m1)} : m1
142
+ [10, 14].each{|i| @conversion_procs[i] = m}
143
+ m2 = method(:to_application_timestamp)
144
+ m = (v != false) ? lambda{|v| convert_date_time(v, &m2)} : m2
145
+ [7, 12].each{|i| @conversion_procs[i] = m}
146
+ @convert_invalid_date_time = v
174
147
  end
175
-
176
- # Executes the given SQL using an available connection, yielding the
177
- # connection if the block is given.
178
- def execute(sql, opts={}, &block)
179
- if opts[:sproc]
180
- call_sproc(sql, opts, &block)
181
- elsif sql.is_a?(Symbol)
182
- execute_prepared_statement(sql, opts, &block)
183
- else
184
- synchronize(opts[:server]){|conn| _execute(conn, sql, opts, &block)}
185
- end
148
+
149
+ # Modify the type translator used for the tinyint type based
150
+ # on the value given.
151
+ def convert_tinyint_to_bool=(v)
152
+ @conversion_procs[1] = TYPE_TRANSLATOR.method(v ? :boolean : :integer)
153
+ @convert_tinyint_to_bool = v
186
154
  end
187
-
155
+
156
+ # Return the number of matched rows when executing a delete/update statement.
157
+ def execute_dui(sql, opts={})
158
+ execute(sql, opts){|c| return affected_rows(c)}
159
+ end
160
+
161
+ # Return the last inserted id when executing an insert statement.
162
+ def execute_insert(sql, opts={})
163
+ execute(sql, opts){|c| return c.insert_id}
164
+ end
165
+
188
166
  # Return the version of the MySQL server two which we are connecting.
189
167
  def server_version(server=nil)
190
168
  @server_version ||= (synchronize(server){|conn| conn.server_version if conn.respond_to?(:server_version)} || super)
@@ -197,7 +175,7 @@ module Sequel
197
175
  # yield the connection if a block is given.
198
176
  def _execute(conn, sql, opts)
199
177
  begin
200
- r = log_yield(sql){conn.query(sql)}
178
+ r = log_yield((log_sql = opts[:log_sql]) ? sql + log_sql : sql){conn.query(sql)}
201
179
  if opts[:type] == :select
202
180
  yield r if r
203
181
  elsif block_given?
@@ -220,7 +198,7 @@ module Sequel
220
198
  end
221
199
  end
222
200
  rescue Mysql::Error => e
223
- raise_error(e, :disconnect=>MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message))
201
+ raise_error(e)
224
202
  ensure
225
203
  r.free if r
226
204
  # Use up all results to avoid a commands out of sync message.
@@ -239,15 +217,51 @@ module Sequel
239
217
  end
240
218
  end
241
219
 
220
+ # Try to get an accurate number of rows matched using the query
221
+ # info. Fall back to affected_rows if there was no match, but
222
+ # that may be inaccurate.
223
+ def affected_rows(conn)
224
+ s = conn.info
225
+ if s && s =~ AFFECTED_ROWS_RE
226
+ $1.to_i
227
+ else
228
+ conn.affected_rows
229
+ end
230
+ end
231
+
242
232
  # MySQL connections use the query method to execute SQL without a result
243
233
  def connection_execute_method
244
234
  :query
245
235
  end
246
236
 
237
+ # If convert_invalid_date_time is nil, :nil, or :string and
238
+ # the conversion raises an InvalidValue exception, return v
239
+ # if :string and nil otherwise.
240
+ def convert_date_time(v)
241
+ begin
242
+ yield v
243
+ rescue InvalidValue
244
+ case @convert_invalid_date_time
245
+ when nil, :nil
246
+ nil
247
+ when :string
248
+ v
249
+ else
250
+ raise
251
+ end
252
+ end
253
+ end
254
+
247
255
  # The MySQL adapter main error class is Mysql::Error
248
256
  def database_error_classes
249
257
  [Mysql::Error]
250
258
  end
259
+
260
+ # Raise a disconnect error if the exception message matches the list
261
+ # of recognized exceptions.
262
+ def disconnect_error?(e, opts)
263
+ super || (e.is_a?(::Mysql::Error) && MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message))
264
+ end
251
265
 
252
266
  # The database name when using the native adapter is always stored in
253
267
  # the :database option.
@@ -262,114 +276,31 @@ module Sequel
262
276
  nil
263
277
  end
264
278
 
265
- # Executes a prepared statement on an available connection. If the
266
- # prepared statement already exists for the connection and has the same
267
- # SQL, reuse it, otherwise, prepare the new statement. Because of the
268
- # usual MySQL stupidity, we are forced to name arguments via separate
269
- # SET queries. Use @sequel_arg_N (for N starting at 1) for these
270
- # arguments.
271
- def execute_prepared_statement(ps_name, opts, &block)
272
- args = opts[:arguments]
273
- ps = prepared_statements[ps_name]
274
- sql = ps.prepared_sql
275
- synchronize(opts[:server]) do |conn|
276
- unless conn.prepared_statements[ps_name] == sql
277
- conn.prepared_statements[ps_name] = sql
278
- _execute(conn, "PREPARE #{ps_name} FROM '#{::Mysql.quote(sql)}'", opts)
279
- end
280
- i = 0
281
- _execute(conn, "SET " + args.map {|arg| "@sequel_arg_#{i+=1} = #{literal(arg)}"}.join(", "), opts) unless args.empty?
282
- _execute(conn, "EXECUTE #{ps_name}#{" USING #{(1..i).map{|j| "@sequel_arg_#{j}"}.join(', ')}" unless i == 0}", opts, &block)
283
- end
284
- end
285
-
286
279
  # Convert tinyint(1) type to boolean if convert_tinyint_to_bool is true
287
280
  def schema_column_type(db_type)
288
- Sequel::MySQL.convert_tinyint_to_bool && db_type == 'tinyint(1)' ? :boolean : super
281
+ convert_tinyint_to_bool && db_type == 'tinyint(1)' ? :boolean : super
289
282
  end
290
283
  end
291
284
 
292
285
  # Dataset class for MySQL datasets accessed via the native driver.
293
286
  class Dataset < Sequel::Dataset
294
287
  include Sequel::MySQL::DatasetMethods
295
- include StoredProcedures
296
-
297
- # Methods to add to MySQL prepared statement calls without using a
298
- # real database prepared statement and bound variables.
299
- module CallableStatementMethods
300
- # Extend given dataset with this module so subselects inside subselects in
301
- # prepared statements work.
302
- def subselect_sql(ds)
303
- ps = ds.to_prepared_statement(:select)
304
- ps.extend(CallableStatementMethods)
305
- ps = ps.bind(@opts[:bind_vars]) if @opts[:bind_vars]
306
- ps.prepared_args = prepared_args
307
- ps.prepared_sql
308
- end
309
- end
310
-
311
- # Methods for MySQL prepared statements using the native driver.
312
- module PreparedStatementMethods
313
- include Sequel::Dataset::UnnumberedArgumentMapper
314
-
315
- private
316
-
317
- # Execute the prepared statement with the bind arguments instead of
318
- # the given SQL.
319
- def execute(sql, opts={}, &block)
320
- super(prepared_statement_name, {:arguments=>bind_arguments}.merge(opts), &block)
321
- end
322
-
323
- # Same as execute, explicit due to intricacies of alias and super.
324
- def execute_dui(sql, opts={}, &block)
325
- super(prepared_statement_name, {:arguments=>bind_arguments}.merge(opts), &block)
326
- end
327
- end
328
-
329
- # Methods for MySQL stored procedures using the native driver.
330
- module StoredProcedureMethods
331
- include Sequel::Dataset::StoredProcedureMethods
332
-
333
- private
334
-
335
- # Execute the database stored procedure with the stored arguments.
336
- def execute(sql, opts={}, &block)
337
- super(@sproc_name, {:args=>@sproc_args, :sproc=>true}.merge(opts), &block)
338
- end
339
-
340
- # Same as execute, explicit due to intricacies of alias and super.
341
- def execute_dui(sql, opts={}, &block)
342
- super(@sproc_name, {:args=>@sproc_args, :sproc=>true}.merge(opts), &block)
343
- end
344
- end
345
-
346
- # MySQL is different in that it supports prepared statements but not bound
347
- # variables outside of prepared statements. The default implementation
348
- # breaks the use of subselects in prepared statements, so extend the
349
- # temporary prepared statement that this creates with a module that
350
- # fixes it.
351
- def call(type, bind_arguments={}, *values, &block)
352
- ps = to_prepared_statement(type, values)
353
- ps.extend(CallableStatementMethods)
354
- ps.call(bind_arguments, &block)
355
- end
356
-
357
- # Delete rows matching this dataset
358
- def delete
359
- execute_dui(delete_sql){|c| return c.affected_rows}
360
- end
361
-
288
+ include Sequel::MySQL::PreparedStatements::DatasetMethods
289
+
290
+ Database::DatasetClass = self
291
+
362
292
  # Yield all rows matching this dataset. If the dataset is set to
363
293
  # split multiple statements, yield arrays of hashes one per statement
364
294
  # instead of yielding results for all statements as hashes.
365
- def fetch_rows(sql, &block)
295
+ def fetch_rows(sql)
366
296
  execute(sql) do |r|
367
297
  i = -1
298
+ cps = db.conversion_procs
368
299
  cols = r.fetch_fields.map do |f|
369
300
  # Pretend tinyint is another integer type if its length is not 1, to
370
301
  # avoid casting to boolean if Sequel::MySQL.convert_tinyint_to_bool
371
302
  # is set.
372
- type_proc = f.type == 1 && f.length != 1 ? MYSQL_TYPES[2] : MYSQL_TYPES[f.type]
303
+ type_proc = f.type == 1 && f.length != 1 ? cps[2] : cps[f.type]
373
304
  [output_identifier(f.name), type_proc, i+=1]
374
305
  end
375
306
  @columns = cols.map{|c| c.first}
@@ -378,7 +309,7 @@ module Sequel
378
309
  yield_rows(r, cols){|h| s << h}
379
310
  yield s
380
311
  else
381
- yield_rows(r, cols, &block)
312
+ yield_rows(r, cols){|h| yield h}
382
313
  end
383
314
  end
384
315
  self
@@ -390,28 +321,6 @@ module Sequel
390
321
  super
391
322
  end
392
323
 
393
- # Insert a new value into this dataset
394
- def insert(*values)
395
- execute_dui(insert_sql(*values)){|c| return c.insert_id}
396
- end
397
-
398
- # Store the given type of prepared statement in the associated database
399
- # with the given name.
400
- def prepare(type, name=nil, *values)
401
- ps = to_prepared_statement(type, values)
402
- ps.extend(PreparedStatementMethods)
403
- if name
404
- ps.prepared_statement_name = name
405
- db.prepared_statements[name] = ps
406
- end
407
- ps
408
- end
409
-
410
- # Replace (update or insert) the matching row.
411
- def replace(*args)
412
- execute_dui(replace_sql(*args)){|c| return c.insert_id}
413
- end
414
-
415
324
  # Makes each yield arrays of rows, with each array containing the rows
416
325
  # for a given result set. Does not work with graphing. So you can submit
417
326
  # SQL with multiple statements and easily determine which statement
@@ -428,11 +337,6 @@ module Sequel
428
337
  ds
429
338
  end
430
339
 
431
- # Update the matching rows.
432
- def update(values={})
433
- execute_dui(update_sql(values)){|c| return c.affected_rows}
434
- end
435
-
436
340
  private
437
341
 
438
342
  # Set the :type option to :select if it hasn't been set.
@@ -440,19 +344,11 @@ module Sequel
440
344
  super(sql, {:type=>:select}.merge(opts), &block)
441
345
  end
442
346
 
443
- # Set the :type option to :dui if it hasn't been set.
444
- def execute_dui(sql, opts={}, &block)
445
- super(sql, {:type=>:dui}.merge(opts), &block)
446
- end
447
-
448
347
  # Handle correct quoting of strings using ::MySQL.quote.
449
- def literal_string(v)
450
- "'#{::Mysql.quote(v)}'"
451
- end
452
-
453
- # Extend the dataset with the MySQL stored procedure methods.
454
- def prepare_extend_sproc(ds)
455
- ds.extend(StoredProcedureMethods)
348
+ def literal_string_append(sql, v)
349
+ sql << "'"
350
+ sql << ::Mysql.quote(v)
351
+ sql << "'"
456
352
  end
457
353
 
458
354
  # Yield each row of the given result set r with columns cols
@@ -1,6 +1,5 @@
1
- require 'mysql2' unless defined? Mysql2
2
-
3
- Sequel.require %w'shared/mysql', 'adapters'
1
+ require 'mysql2'
2
+ Sequel.require %w'shared/mysql_prepared_statements', 'adapters'
4
3
 
5
4
  module Sequel
6
5
  # Module for holding all Mysql2-related classes and modules for Sequel.
@@ -8,11 +7,21 @@ module Sequel
8
7
  # Database class for MySQL databases used with Sequel.
9
8
  class Database < Sequel::Database
10
9
  include Sequel::MySQL::DatabaseMethods
10
+ include Sequel::MySQL::PreparedStatements::DatabaseMethods
11
11
 
12
12
  # Mysql::Error messages that indicate the current connection should be disconnected
13
- MYSQL_DATABASE_DISCONNECT_ERRORS = /\A(Commands out of sync; you can't run this command now|Can't connect to local MySQL server through socket|MySQL server has gone away)/
13
+ MYSQL_DATABASE_DISCONNECT_ERRORS = /\A(Commands out of sync; you can't run this command now|Can't connect to local MySQL server through socket|MySQL server has gone away|This connection is still waiting for a result, try again once you have the result|closed MySQL connection)/
14
14
 
15
15
  set_adapter_scheme :mysql2
16
+
17
+ # Whether to convert tinyint columns to bool for this database
18
+ attr_accessor :convert_tinyint_to_bool
19
+
20
+ # Set the convert_tinyint_to_bool setting based on the default value.
21
+ def initialize(opts={})
22
+ super
23
+ self.convert_tinyint_to_bool = Sequel::MySQL.convert_tinyint_to_bool
24
+ end
16
25
 
17
26
  # Connect to the database. In addition to the usual database options,
18
27
  # the following options have effect:
@@ -21,7 +30,6 @@ module Sequel
21
30
  # a filter for an autoincrement column equals NULL to return the last
22
31
  # inserted row.
23
32
  # * :charset - Same as :encoding (:encoding takes precendence)
24
- # * :compress - Set to false to not compress results from the server
25
33
  # * :config_default_group - The default group to read from the in
26
34
  # the MySQL config file.
27
35
  # * :config_local_infile - If provided, sets the Mysql::OPT_LOCAL_INFILE
@@ -37,42 +45,33 @@ module Sequel
37
45
  opts = server_opts(server)
38
46
  opts[:host] ||= 'localhost'
39
47
  opts[:username] ||= opts[:user]
48
+ opts[:flags] = ::Mysql2::Client::FOUND_ROWS if ::Mysql2::Client.const_defined?(:FOUND_ROWS)
40
49
  conn = ::Mysql2::Client.new(opts)
41
50
 
42
- sqls = []
51
+ sqls = mysql_connection_setting_sqls
52
+
43
53
  # Set encoding a slightly different way after connecting,
44
54
  # in case the READ_DEFAULT_GROUP overrode the provided encoding.
45
55
  # Doesn't work across implicit reconnects, but Sequel doesn't turn on
46
56
  # that feature.
47
57
  if encoding = opts[:encoding] || opts[:charset]
48
- sqls << "SET NAMES #{conn.escape(encoding.to_s)}"
58
+ sqls.unshift("SET NAMES #{conn.escape(encoding.to_s)}")
49
59
  end
50
60
 
51
- # Increase timeout so mysql server doesn't disconnect us.
52
- # Value used by default is maximum allowed value on Windows.
53
- sqls << "SET @@wait_timeout = #{opts[:timeout] || 2147483}"
54
-
55
- # By default, MySQL 'where id is null' selects the last inserted id
56
- sqls << "SET SQL_AUTO_IS_NULL=0" unless opts[:auto_is_null]
57
-
58
61
  sqls.each{|sql| log_yield(sql){conn.query(sql)}}
59
62
 
63
+ add_prepared_statements_cache(conn)
60
64
  conn
61
65
  end
62
66
 
63
- # Returns instance of Sequel::MySQL::Dataset with the given options.
64
- def dataset(opts = nil)
65
- Mysql2::Dataset.new(self, opts)
67
+ # Return the number of matched rows when executing a delete/update statement.
68
+ def execute_dui(sql, opts={})
69
+ execute(sql, opts){|c| return c.affected_rows}
66
70
  end
67
71
 
68
- # Executes the given SQL using an available connection, yielding the
69
- # connection if the block is given.
70
- def execute(sql, opts={}, &block)
71
- if opts[:sproc]
72
- call_sproc(sql, opts, &block)
73
- else
74
- synchronize(opts[:server]){|conn| _execute(conn, sql, opts, &block)}
75
- end
72
+ # Return the last inserted id when executing an insert statement.
73
+ def execute_insert(sql, opts={})
74
+ execute(sql, opts){|c| return c.last_id}
76
75
  end
77
76
 
78
77
  # Return the version of the MySQL server two which we are connecting.
@@ -87,14 +86,14 @@ module Sequel
87
86
  # yield the connection if a block is given.
88
87
  def _execute(conn, sql, opts)
89
88
  begin
90
- r = log_yield(sql){conn.query(sql, :symbolize_keys => true, :database_timezone => Sequel.database_timezone, :application_timezone => Sequel.application_timezone)}
89
+ r = log_yield((log_sql = opts[:log_sql]) ? sql + log_sql : sql){conn.query(sql, :symbolize_keys => true, :database_timezone => timezone, :application_timezone => Sequel.application_timezone)}
91
90
  if opts[:type] == :select
92
91
  yield r if r
93
92
  elsif block_given?
94
93
  yield conn
95
94
  end
96
95
  rescue ::Mysql2::Error => e
97
- raise_error(e, :disconnect=>MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message))
96
+ raise_error(e)
98
97
  end
99
98
  end
100
99
 
@@ -108,6 +107,17 @@ module Sequel
108
107
  [::Mysql2::Error]
109
108
  end
110
109
 
110
+ # If a connection object is available, try pinging it. Otherwise, if the
111
+ # error is a Mysql2::Error, check the SQL state and exception message for
112
+ # disconnects.
113
+ def disconnect_error?(e, opts)
114
+ super ||
115
+ ((conn = opts[:conn]) && !conn.ping) ||
116
+ (e.is_a?(::Mysql2::Error) &&
117
+ (e.sql_state =~ /\A08/ ||
118
+ MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message)))
119
+ end
120
+
111
121
  # The database name when using the native adapter is always stored in
112
122
  # the :database option.
113
123
  def database_name
@@ -121,43 +131,39 @@ module Sequel
121
131
 
122
132
  # Convert tinyint(1) type to boolean if convert_tinyint_to_bool is true
123
133
  def schema_column_type(db_type)
124
- Sequel::MySQL.convert_tinyint_to_bool && db_type == 'tinyint(1)' ? :boolean : super
134
+ convert_tinyint_to_bool && db_type == 'tinyint(1)' ? :boolean : super
125
135
  end
126
136
  end
127
137
 
128
138
  # Dataset class for MySQL datasets accessed via the native driver.
129
139
  class Dataset < Sequel::Dataset
130
140
  include Sequel::MySQL::DatasetMethods
141
+ include Sequel::MySQL::PreparedStatements::DatasetMethods
131
142
 
132
- # Delete rows matching this dataset
133
- def delete
134
- execute_dui(delete_sql){|c| return c.affected_rows}
135
- end
143
+ Database::DatasetClass = self
136
144
 
137
145
  # Yield all rows matching this dataset.
138
- def fetch_rows(sql, &block)
146
+ def fetch_rows(sql)
139
147
  execute(sql) do |r|
140
- @columns = r.fields
141
- r.each(:cast_booleans => Sequel::MySQL.convert_tinyint_to_bool, &block)
148
+ if identifier_output_method
149
+ cols = r.fields
150
+ @columns = cols2 = cols.map{|c| output_identifier(c.to_s)}
151
+ cs = cols.zip(cols2)
152
+ r.each(:cast_booleans => db.convert_tinyint_to_bool) do |row|
153
+ h = {}
154
+ cs.each do |a, b|
155
+ h[b] = row[a]
156
+ end
157
+ yield h
158
+ end
159
+ else
160
+ @columns = r.fields
161
+ r.each(:cast_booleans => db.convert_tinyint_to_bool){|h| yield h}
162
+ end
142
163
  end
143
164
  self
144
165
  end
145
166
 
146
- # Insert a new value into this dataset
147
- def insert(*values)
148
- execute_dui(insert_sql(*values)){|c| return c.last_id}
149
- end
150
-
151
- # Replace (update or insert) the matching row.
152
- def replace(*args)
153
- execute_dui(replace_sql(*args)){|c| return c.last_id}
154
- end
155
-
156
- # Update the matching rows.
157
- def update(values={})
158
- execute_dui(update_sql(values)){|c| return c.affected_rows}
159
- end
160
-
161
167
  private
162
168
 
163
169
  # Set the :type option to :select if it hasn't been set.
@@ -165,14 +171,9 @@ module Sequel
165
171
  super(sql, {:type=>:select}.merge(opts), &block)
166
172
  end
167
173
 
168
- # Set the :type option to :dui if it hasn't been set.
169
- def execute_dui(sql, opts={}, &block)
170
- super(sql, {:type=>:dui}.merge(opts), &block)
171
- end
172
-
173
174
  # Handle correct quoting of strings using ::Mysql2::Client#escape.
174
- def literal_string(v)
175
- db.synchronize{|c| "'#{c.escape(v)}'"}
175
+ def literal_string_append(sql, v)
176
+ sql << "'" << db.synchronize{|c| c.escape(v)} << "'"
176
177
  end
177
178
  end
178
179
  end