sequel 3.21.0 → 3.39.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 (352) hide show
  1. data/CHANGELOG +1061 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +103 -63
  4. data/Rakefile +59 -27
  5. data/bin/sequel +50 -26
  6. data/doc/active_record.rdoc +67 -51
  7. data/doc/advanced_associations.rdoc +189 -75
  8. data/doc/association_basics.rdoc +327 -79
  9. data/doc/cheat_sheet.rdoc +21 -21
  10. data/doc/core_extensions.rdoc +374 -0
  11. data/doc/dataset_basics.rdoc +10 -10
  12. data/doc/dataset_filtering.rdoc +54 -42
  13. data/doc/mass_assignment.rdoc +56 -0
  14. data/doc/migration.rdoc +89 -557
  15. data/doc/model_hooks.rdoc +80 -29
  16. data/doc/object_model.rdoc +547 -0
  17. data/doc/opening_databases.rdoc +114 -53
  18. data/doc/prepared_statements.rdoc +41 -15
  19. data/doc/querying.rdoc +137 -56
  20. data/doc/reflection.rdoc +36 -10
  21. data/doc/release_notes/3.22.0.txt +39 -0
  22. data/doc/release_notes/3.23.0.txt +172 -0
  23. data/doc/release_notes/3.24.0.txt +420 -0
  24. data/doc/release_notes/3.25.0.txt +88 -0
  25. data/doc/release_notes/3.26.0.txt +88 -0
  26. data/doc/release_notes/3.27.0.txt +82 -0
  27. data/doc/release_notes/3.28.0.txt +304 -0
  28. data/doc/release_notes/3.29.0.txt +459 -0
  29. data/doc/release_notes/3.30.0.txt +135 -0
  30. data/doc/release_notes/3.31.0.txt +146 -0
  31. data/doc/release_notes/3.32.0.txt +202 -0
  32. data/doc/release_notes/3.33.0.txt +157 -0
  33. data/doc/release_notes/3.34.0.txt +671 -0
  34. data/doc/release_notes/3.35.0.txt +144 -0
  35. data/doc/release_notes/3.36.0.txt +245 -0
  36. data/doc/release_notes/3.37.0.txt +338 -0
  37. data/doc/release_notes/3.38.0.txt +234 -0
  38. data/doc/release_notes/3.39.0.txt +237 -0
  39. data/doc/schema_modification.rdoc +585 -0
  40. data/doc/sharding.rdoc +99 -8
  41. data/doc/sql.rdoc +154 -112
  42. data/doc/testing.rdoc +169 -0
  43. data/doc/thread_safety.rdoc +17 -0
  44. data/doc/transactions.rdoc +137 -0
  45. data/doc/validations.rdoc +1 -1
  46. data/doc/virtual_rows.rdoc +78 -43
  47. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  48. data/lib/sequel/adapters/ado.rb +40 -18
  49. data/lib/sequel/adapters/amalgalite.rb +17 -9
  50. data/lib/sequel/adapters/db2.rb +175 -86
  51. data/lib/sequel/adapters/dbi.rb +15 -15
  52. data/lib/sequel/adapters/do/mysql.rb +17 -11
  53. data/lib/sequel/adapters/do/postgres.rb +2 -61
  54. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  55. data/lib/sequel/adapters/do.rb +18 -36
  56. data/lib/sequel/adapters/firebird.rb +27 -208
  57. data/lib/sequel/adapters/ibmdb.rb +453 -0
  58. data/lib/sequel/adapters/informix.rb +6 -23
  59. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  60. data/lib/sequel/adapters/jdbc/db2.rb +56 -0
  61. data/lib/sequel/adapters/jdbc/derby.rb +325 -0
  62. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  63. data/lib/sequel/adapters/jdbc/h2.rb +73 -31
  64. data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
  65. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  66. data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
  67. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  68. data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
  69. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  70. data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
  71. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  72. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  73. data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
  74. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  75. data/lib/sequel/adapters/jdbc.rb +279 -97
  76. data/lib/sequel/adapters/mock.rb +372 -0
  77. data/lib/sequel/adapters/mysql.rb +125 -222
  78. data/lib/sequel/adapters/mysql2.rb +65 -56
  79. data/lib/sequel/adapters/odbc/mssql.rb +17 -9
  80. data/lib/sequel/adapters/odbc.rb +28 -9
  81. data/lib/sequel/adapters/openbase.rb +3 -5
  82. data/lib/sequel/adapters/oracle.rb +349 -53
  83. data/lib/sequel/adapters/postgres.rb +368 -138
  84. data/lib/sequel/adapters/shared/access.rb +32 -9
  85. data/lib/sequel/adapters/shared/db2.rb +343 -0
  86. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  87. data/lib/sequel/adapters/shared/informix.rb +53 -0
  88. data/lib/sequel/adapters/shared/mssql.rb +401 -116
  89. data/lib/sequel/adapters/shared/mysql.rb +424 -89
  90. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
  91. data/lib/sequel/adapters/shared/oracle.rb +257 -45
  92. data/lib/sequel/adapters/shared/postgres.rb +675 -279
  93. data/lib/sequel/adapters/shared/progress.rb +5 -8
  94. data/lib/sequel/adapters/shared/sqlite.rb +285 -96
  95. data/lib/sequel/adapters/sqlite.rb +101 -39
  96. data/lib/sequel/adapters/swift/mysql.rb +10 -12
  97. data/lib/sequel/adapters/swift/postgres.rb +13 -79
  98. data/lib/sequel/adapters/swift/sqlite.rb +9 -6
  99. data/lib/sequel/adapters/swift.rb +28 -19
  100. data/lib/sequel/adapters/tinytds.rb +174 -22
  101. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
  102. data/lib/sequel/adapters/utils/pg_types.rb +81 -0
  103. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  104. data/lib/sequel/ast_transformer.rb +194 -0
  105. data/lib/sequel/connection_pool/sharded_single.rb +11 -1
  106. data/lib/sequel/connection_pool/sharded_threaded.rb +33 -2
  107. data/lib/sequel/connection_pool/single.rb +5 -0
  108. data/lib/sequel/connection_pool/threaded.rb +43 -14
  109. data/lib/sequel/connection_pool.rb +10 -2
  110. data/lib/sequel/core.rb +143 -11
  111. data/lib/sequel/database/connecting.rb +38 -28
  112. data/lib/sequel/database/dataset.rb +4 -4
  113. data/lib/sequel/database/dataset_defaults.rb +63 -2
  114. data/lib/sequel/database/logging.rb +7 -2
  115. data/lib/sequel/database/misc.rb +190 -46
  116. data/lib/sequel/database/query.rb +272 -110
  117. data/lib/sequel/database/schema_generator.rb +103 -36
  118. data/lib/sequel/database/schema_methods.rb +300 -67
  119. data/lib/sequel/dataset/actions.rb +344 -90
  120. data/lib/sequel/dataset/features.rb +101 -8
  121. data/lib/sequel/dataset/graph.rb +42 -15
  122. data/lib/sequel/dataset/misc.rb +52 -25
  123. data/lib/sequel/dataset/mutation.rb +12 -7
  124. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  125. data/lib/sequel/dataset/query.rb +305 -54
  126. data/lib/sequel/dataset/sql.rb +720 -292
  127. data/lib/sequel/dataset.rb +8 -0
  128. data/lib/sequel/exceptions.rb +4 -0
  129. data/lib/sequel/extensions/_pretty_table.rb +83 -0
  130. data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
  131. data/lib/sequel/extensions/blank.rb +4 -0
  132. data/lib/sequel/extensions/columns_introspection.rb +72 -0
  133. data/lib/sequel/extensions/constraint_validations.rb +451 -0
  134. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
  135. data/lib/sequel/extensions/eval_inspect.rb +173 -0
  136. data/lib/sequel/extensions/inflector.rb +4 -0
  137. data/lib/sequel/extensions/looser_typecasting.rb +5 -4
  138. data/lib/sequel/extensions/migration.rb +100 -11
  139. data/lib/sequel/extensions/named_timezones.rb +9 -0
  140. data/lib/sequel/extensions/null_dataset.rb +94 -0
  141. data/lib/sequel/extensions/pagination.rb +4 -0
  142. data/lib/sequel/extensions/pg_array.rb +537 -0
  143. data/lib/sequel/extensions/pg_array_ops.rb +263 -0
  144. data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
  145. data/lib/sequel/extensions/pg_hstore.rb +313 -0
  146. data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
  147. data/lib/sequel/extensions/pg_inet.rb +113 -0
  148. data/lib/sequel/extensions/pg_interval.rb +191 -0
  149. data/lib/sequel/extensions/pg_json.rb +208 -0
  150. data/lib/sequel/extensions/pg_range.rb +512 -0
  151. data/lib/sequel/extensions/pg_range_ops.rb +150 -0
  152. data/lib/sequel/extensions/pg_row.rb +572 -0
  153. data/lib/sequel/extensions/pg_row_ops.rb +182 -0
  154. data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
  155. data/lib/sequel/extensions/pretty_table.rb +17 -72
  156. data/lib/sequel/extensions/query.rb +8 -4
  157. data/lib/sequel/extensions/query_literals.rb +79 -0
  158. data/lib/sequel/extensions/schema_caching.rb +76 -0
  159. data/lib/sequel/extensions/schema_dumper.rb +282 -76
  160. data/lib/sequel/extensions/select_remove.rb +39 -0
  161. data/lib/sequel/extensions/server_block.rb +140 -0
  162. data/lib/sequel/extensions/split_array_nil.rb +65 -0
  163. data/lib/sequel/extensions/sql_expr.rb +8 -110
  164. data/lib/sequel/extensions/string_date_time.rb +4 -0
  165. data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
  166. data/lib/sequel/extensions/to_dot.rb +99 -83
  167. data/lib/sequel/model/associations.rb +1263 -409
  168. data/lib/sequel/model/base.rb +624 -171
  169. data/lib/sequel/model/errors.rb +1 -1
  170. data/lib/sequel/model/exceptions.rb +24 -2
  171. data/lib/sequel/model/inflections.rb +1 -1
  172. data/lib/sequel/model.rb +30 -11
  173. data/lib/sequel/no_core_ext.rb +2 -0
  174. data/lib/sequel/plugins/active_model.rb +13 -1
  175. data/lib/sequel/plugins/association_pks.rb +22 -4
  176. data/lib/sequel/plugins/caching.rb +25 -18
  177. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  178. data/lib/sequel/plugins/composition.rb +44 -12
  179. data/lib/sequel/plugins/constraint_validations.rb +198 -0
  180. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  181. data/lib/sequel/plugins/defaults_setter.rb +72 -0
  182. data/lib/sequel/plugins/dirty.rb +214 -0
  183. data/lib/sequel/plugins/eager_each.rb +59 -0
  184. data/lib/sequel/plugins/force_encoding.rb +6 -6
  185. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  186. data/lib/sequel/plugins/identity_map.rb +134 -15
  187. data/lib/sequel/plugins/instance_filters.rb +10 -0
  188. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  189. data/lib/sequel/plugins/json_serializer.rb +58 -6
  190. data/lib/sequel/plugins/list.rb +13 -2
  191. data/lib/sequel/plugins/many_through_many.rb +103 -51
  192. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  193. data/lib/sequel/plugins/nested_attributes.rb +150 -66
  194. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  195. data/lib/sequel/plugins/pg_row.rb +121 -0
  196. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  197. data/lib/sequel/plugins/prepared_statements.rb +167 -0
  198. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  199. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  200. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  201. data/lib/sequel/plugins/rcte_tree.rb +31 -17
  202. data/lib/sequel/plugins/schema.rb +8 -3
  203. data/lib/sequel/plugins/serialization.rb +98 -49
  204. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  205. data/lib/sequel/plugins/sharding.rb +21 -54
  206. data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
  207. data/lib/sequel/plugins/static_cache.rb +99 -0
  208. data/lib/sequel/plugins/subclasses.rb +29 -3
  209. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  210. data/lib/sequel/plugins/timestamps.rb +1 -1
  211. data/lib/sequel/plugins/tree.rb +3 -3
  212. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  213. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  214. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  215. data/lib/sequel/plugins/validation_helpers.rb +55 -4
  216. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  217. data/lib/sequel/sql.rb +649 -122
  218. data/lib/sequel/timezones.rb +67 -40
  219. data/lib/sequel/version.rb +1 -1
  220. data/spec/adapters/db2_spec.rb +146 -0
  221. data/spec/adapters/firebird_spec.rb +1 -1
  222. data/spec/adapters/mssql_spec.rb +194 -66
  223. data/spec/adapters/mysql_spec.rb +475 -306
  224. data/spec/adapters/oracle_spec.rb +92 -117
  225. data/spec/adapters/postgres_spec.rb +1982 -325
  226. data/spec/adapters/spec_helper.rb +9 -6
  227. data/spec/adapters/sqlite_spec.rb +203 -75
  228. data/spec/core/connection_pool_spec.rb +218 -93
  229. data/spec/core/database_spec.rb +956 -522
  230. data/spec/core/dataset_spec.rb +1631 -1242
  231. data/spec/core/expression_filters_spec.rb +690 -334
  232. data/spec/core/mock_adapter_spec.rb +453 -0
  233. data/spec/core/object_graph_spec.rb +88 -129
  234. data/spec/core/schema_generator_spec.rb +4 -4
  235. data/spec/core/schema_spec.rb +556 -53
  236. data/spec/core/spec_helper.rb +7 -48
  237. data/spec/core_extensions_spec.rb +626 -0
  238. data/spec/extensions/active_model_spec.rb +13 -0
  239. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  240. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  241. data/spec/extensions/association_dependencies_spec.rb +15 -25
  242. data/spec/extensions/association_pks_spec.rb +66 -32
  243. data/spec/extensions/association_proxies_spec.rb +4 -4
  244. data/spec/extensions/boolean_readers_spec.rb +25 -25
  245. data/spec/extensions/caching_spec.rb +47 -51
  246. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  247. data/spec/extensions/columns_introspection_spec.rb +91 -0
  248. data/spec/extensions/composition_spec.rb +18 -13
  249. data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
  250. data/spec/extensions/constraint_validations_spec.rb +316 -0
  251. data/spec/extensions/dataset_associations_spec.rb +199 -0
  252. data/spec/extensions/defaults_setter_spec.rb +88 -0
  253. data/spec/extensions/dirty_spec.rb +155 -0
  254. data/spec/extensions/eager_each_spec.rb +34 -0
  255. data/spec/extensions/eval_inspect_spec.rb +67 -0
  256. data/spec/extensions/force_encoding_spec.rb +4 -2
  257. data/spec/extensions/hook_class_methods_spec.rb +97 -128
  258. data/spec/extensions/identity_map_spec.rb +142 -24
  259. data/spec/extensions/inflector_spec.rb +0 -4
  260. data/spec/extensions/instance_filters_spec.rb +11 -21
  261. data/spec/extensions/instance_hooks_spec.rb +72 -0
  262. data/spec/extensions/json_serializer_spec.rb +49 -12
  263. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  264. data/spec/extensions/list_spec.rb +49 -40
  265. data/spec/extensions/looser_typecasting_spec.rb +7 -7
  266. data/spec/extensions/many_through_many_spec.rb +368 -254
  267. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  268. data/spec/extensions/migration_spec.rb +140 -35
  269. data/spec/extensions/named_timezones_spec.rb +29 -11
  270. data/spec/extensions/nested_attributes_spec.rb +268 -89
  271. data/spec/extensions/null_dataset_spec.rb +85 -0
  272. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  273. data/spec/extensions/pg_array_ops_spec.rb +112 -0
  274. data/spec/extensions/pg_array_spec.rb +320 -0
  275. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  276. data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
  277. data/spec/extensions/pg_hstore_spec.rb +194 -0
  278. data/spec/extensions/pg_inet_spec.rb +47 -0
  279. data/spec/extensions/pg_interval_spec.rb +72 -0
  280. data/spec/extensions/pg_json_spec.rb +99 -0
  281. data/spec/extensions/pg_range_ops_spec.rb +56 -0
  282. data/spec/extensions/pg_range_spec.rb +395 -0
  283. data/spec/extensions/pg_row_ops_spec.rb +58 -0
  284. data/spec/extensions/pg_row_plugin_spec.rb +49 -0
  285. data/spec/extensions/pg_row_spec.rb +323 -0
  286. data/spec/extensions/pg_statement_cache_spec.rb +208 -0
  287. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  288. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  289. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  290. data/spec/extensions/prepared_statements_spec.rb +87 -0
  291. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  292. data/spec/extensions/pretty_table_spec.rb +7 -6
  293. data/spec/extensions/query_literals_spec.rb +167 -0
  294. data/spec/extensions/query_spec.rb +9 -3
  295. data/spec/extensions/rcte_tree_spec.rb +50 -43
  296. data/spec/extensions/schema_caching_spec.rb +41 -0
  297. data/spec/extensions/schema_dumper_spec.rb +434 -49
  298. data/spec/extensions/schema_spec.rb +30 -49
  299. data/spec/extensions/select_remove_spec.rb +38 -0
  300. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  301. data/spec/extensions/serialization_spec.rb +86 -48
  302. data/spec/extensions/server_block_spec.rb +90 -0
  303. data/spec/extensions/sharding_spec.rb +69 -143
  304. data/spec/extensions/single_table_inheritance_spec.rb +23 -29
  305. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  306. data/spec/extensions/spec_helper.rb +34 -67
  307. data/spec/extensions/split_array_nil_spec.rb +24 -0
  308. data/spec/extensions/sql_expr_spec.rb +29 -60
  309. data/spec/extensions/static_cache_spec.rb +145 -0
  310. data/spec/extensions/subclasses_spec.rb +14 -0
  311. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  312. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  313. data/spec/extensions/timestamps_spec.rb +6 -6
  314. data/spec/extensions/to_dot_spec.rb +8 -11
  315. data/spec/extensions/touch_spec.rb +13 -14
  316. data/spec/extensions/tree_spec.rb +11 -26
  317. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  318. data/spec/extensions/update_primary_key_spec.rb +30 -24
  319. data/spec/extensions/validation_class_methods_spec.rb +58 -67
  320. data/spec/extensions/validation_helpers_spec.rb +31 -37
  321. data/spec/extensions/xml_serializer_spec.rb +29 -4
  322. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  323. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  324. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  325. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  326. data/spec/integration/associations_test.rb +659 -21
  327. data/spec/integration/database_test.rb +11 -5
  328. data/spec/integration/dataset_test.rb +717 -129
  329. data/spec/integration/eager_loader_test.rb +38 -54
  330. data/spec/integration/migrator_test.rb +2 -3
  331. data/spec/integration/model_test.rb +81 -2
  332. data/spec/integration/plugin_test.rb +604 -147
  333. data/spec/integration/prepared_statement_test.rb +272 -128
  334. data/spec/integration/schema_test.rb +367 -57
  335. data/spec/integration/spec_helper.rb +42 -32
  336. data/spec/integration/timezone_test.rb +38 -12
  337. data/spec/integration/transaction_test.rb +183 -8
  338. data/spec/integration/type_test.rb +31 -8
  339. data/spec/model/association_reflection_spec.rb +207 -8
  340. data/spec/model/associations_spec.rb +1206 -693
  341. data/spec/model/base_spec.rb +334 -100
  342. data/spec/model/dataset_methods_spec.rb +45 -27
  343. data/spec/model/eager_loading_spec.rb +828 -692
  344. data/spec/model/hooks_spec.rb +355 -67
  345. data/spec/model/model_spec.rb +251 -179
  346. data/spec/model/plugins_spec.rb +24 -13
  347. data/spec/model/record_spec.rb +506 -232
  348. data/spec/model/spec_helper.rb +16 -77
  349. data/spec/model/validations_spec.rb +38 -2
  350. data/spec/rcov.opts +2 -0
  351. metadata +209 -80
  352. data/spec/core/core_sql_spec.rb +0 -451
@@ -1,7 +1,7 @@
1
1
  module Sequel
2
2
  class Database
3
3
  # ---------------------
4
- # :section: Methods that execute queries and/or return results
4
+ # :section: 1 - Methods that execute queries and/or return results
5
5
  # This methods generally execute SQL code on the database server.
6
6
  # ---------------------
7
7
 
@@ -21,10 +21,10 @@ module Sequel
21
21
  :repeatable=>'REPEATABLE READ'.freeze,
22
22
  :serializable=>'SERIALIZABLE'.freeze}
23
23
 
24
- POSTGRES_DEFAULT_RE = /\A(?:B?('.*')::[^']+|\((-?\d+(?:\.\d+)?)\))\z/
25
- MSSQL_DEFAULT_RE = /\A(?:\(N?('.*')\)|\(\((-?\d+(?:\.\d+)?)\)\))\z/
26
- MYSQL_TIMESTAMP_RE = /\ACURRENT_(?:DATE|TIMESTAMP)?\z/
27
24
  STRING_DEFAULT_RE = /\A'(.*)'\z/
25
+ CURRENT_TIMESTAMP_RE = /now|CURRENT|getdate/io
26
+ COLUMN_SCHEMA_DATETIME_TYPES = [:date, :datetime]
27
+ COLUMN_SCHEMA_STRING_TYPES = [:string, :blob, :date, :datetime, :time, :enum, :set, :interval]
28
28
 
29
29
  # The prepared statement object hash for this database, keyed by name symbol
30
30
  attr_reader :prepared_statements
@@ -35,11 +35,19 @@ module Sequel
35
35
  # Database#transaction, as on MSSQL if affects all future transactions
36
36
  # on the same connection.
37
37
  attr_accessor :transaction_isolation_level
38
+
39
+ # Whether the schema should be cached for this database. True by default
40
+ # for performance, can be set to false to always issue a database query to
41
+ # get the schema.
42
+ attr_accessor :cache_schema
38
43
 
39
44
  # Runs the supplied SQL statement string on the database server.
40
- # Alias for run.
45
+ # Returns self so it can be safely chained:
46
+ #
47
+ # DB << "UPDATE albums SET artist_id = NULL" << "DROP TABLE artists"
41
48
  def <<(sql)
42
49
  run(sql)
50
+ self
43
51
  end
44
52
 
45
53
  # Call the prepared statement with the given name with the given hash
@@ -47,8 +55,8 @@ module Sequel
47
55
  #
48
56
  # DB[:items].filter(:id=>1).prepare(:first, :sa)
49
57
  # DB.call(:sa) # SELECT * FROM items WHERE id = 1
50
- def call(ps_name, hash={})
51
- prepared_statements[ps_name].call(hash)
58
+ def call(ps_name, hash={}, &block)
59
+ prepared_statement(ps_name).call(hash, &block)
52
60
  end
53
61
 
54
62
  # Executes the given SQL on the database. This method should be overridden in descendants.
@@ -78,16 +86,34 @@ module Sequel
78
86
  execute_dui(sql, opts, &block)
79
87
  end
80
88
 
89
+ # Returns an array of hashes containing foreign key information from the
90
+ # table. Each hash will contain at least the following fields:
91
+ #
92
+ # :columns :: An array of columns in the given table
93
+ # :table :: The table referenced by the columns
94
+ # :key :: An array of columns referenced (in the table specified by :table),
95
+ # but can be nil on certain adapters if the primary key is referenced.
96
+ #
97
+ # The hash may also contain entries for:
98
+ #
99
+ # :deferrable :: Whether the constraint is deferrable
100
+ # :name :: The name of the constraint
101
+ # :on_delete :: The action to take ON DELETE
102
+ # :on_update :: The action to take ON UPDATE
103
+ def foreign_key_list(table, opts={})
104
+ raise NotImplemented, "#foreign_key_list should be overridden by adapters"
105
+ end
106
+
81
107
  # Returns a single value from the database, e.g.:
82
108
  #
83
109
  # DB.get(1) # SELECT 1
84
110
  # # => 1
85
- # DB.get{version{}} # SELECT server_version()
111
+ # DB.get{server_version{}} # SELECT server_version()
86
112
  def get(*args, &block)
87
113
  dataset.get(*args, &block)
88
114
  end
89
115
 
90
- # Return a hash containing index information. Hash keys are index name symbols.
116
+ # Return a hash containing index information for the table. Hash keys are index name symbols.
91
117
  # Values are subhashes with two keys, :columns and :unique. The value of :columns
92
118
  # is an array of symbols of column names. The value of :unique is true or false
93
119
  # depending on if the index is unique.
@@ -110,17 +136,17 @@ module Sequel
110
136
  nil
111
137
  end
112
138
 
113
- # Parse the schema from the database.
114
139
  # Returns the schema for the given table as an array with all members being arrays of length 2,
115
140
  # the first member being the column name, and the second member being a hash of column information.
141
+ # The table argument can also be a dataset, as long as it only has one table.
116
142
  # Available options are:
117
143
  #
118
144
  # :reload :: Ignore any cached results, and get fresh information from the database.
119
145
  # :schema :: An explicit schema to use. It may also be implicitly provided
120
146
  # via the table name.
121
147
  #
122
- # If schema parsing is supported by the database, the column information should at least contain the
123
- # following columns:
148
+ # If schema parsing is supported by the database, the column information should hash at least contain the
149
+ # following entries:
124
150
  #
125
151
  # :allow_null :: Whether NULL is an allowed value for the column.
126
152
  # :db_type :: The database type for the column, as a database specific string.
@@ -129,7 +155,8 @@ module Sequel
129
155
  # it means that primary key information is unavailable, not that the column
130
156
  # is not a primary key.
131
157
  # :ruby_default :: The database default for the column, as a ruby object. In many cases, complex
132
- # database defaults cannot be parsed into ruby objects.
158
+ # database defaults cannot be parsed into ruby objects, in which case nil will be
159
+ # used as the value.
133
160
  # :type :: A symbol specifying the type, such as :integer or :string.
134
161
  #
135
162
  # Example:
@@ -152,32 +179,48 @@ module Sequel
152
179
  def schema(table, opts={})
153
180
  raise(Error, 'schema parsing is not implemented on this database') unless respond_to?(:schema_parse_table, true)
154
181
 
155
- sch, table_name = schema_and_table(table)
156
- quoted_name = quote_schema_table(table)
157
- opts = opts.merge(:schema=>sch) if sch && !opts.include?(:schema)
182
+ opts = opts.dup
183
+ if table.is_a?(Dataset)
184
+ o = table.opts
185
+ from = o[:from]
186
+ raise(Error, "can only parse the schema for a dataset with a single from table") unless from && from.length == 1 && !o.include?(:join) && !o.include?(:sql)
187
+ tab = table.first_source_table
188
+ sch, table_name = schema_and_table(tab)
189
+ quoted_name = table.literal(tab)
190
+ opts[:dataset] = table
191
+ else
192
+ sch, table_name = schema_and_table(table)
193
+ quoted_name = quote_schema_table(table)
194
+ end
195
+ opts[:schema] = sch if sch && !opts.include?(:schema)
158
196
 
159
- @schemas.delete(quoted_name) if opts[:reload]
160
- return @schemas[quoted_name] if @schemas[quoted_name]
197
+ Sequel.synchronize{@schemas.delete(quoted_name)} if opts[:reload]
198
+ return Sequel.synchronize{@schemas[quoted_name]} if @schemas[quoted_name]
161
199
 
162
200
  cols = schema_parse_table(table_name, opts)
163
201
  raise(Error, 'schema parsing returned no columns, table probably doesn\'t exist') if cols.nil? || cols.empty?
164
202
  cols.each{|_,c| c[:ruby_default] = column_schema_to_ruby_default(c[:default], c[:type])}
165
- @schemas[quoted_name] = cols
203
+ Sequel.synchronize{@schemas[quoted_name] = cols} if cache_schema
204
+ cols
166
205
  end
167
206
 
168
207
  # Returns true if a table with the given name exists. This requires a query
169
208
  # to the database.
170
209
  #
171
210
  # DB.table_exists?(:foo) # => false
211
+ # # SELECT NULL FROM foo LIMIT 1
212
+ #
213
+ # Note that since this does a SELECT from the table, it can give false negatives
214
+ # if you don't have permission to SELECT from the table.
172
215
  def table_exists?(name)
173
- begin
174
- from(name).first
175
- true
176
- rescue
177
- false
178
- end
216
+ sch, table_name = schema_and_table(name)
217
+ name = SQL::QualifiedIdentifier.new(sch, table_name) if sch
218
+ _table_exists?(from(name))
219
+ true
220
+ rescue DatabaseError
221
+ false
179
222
  end
180
-
223
+
181
224
  # Return all tables in the database as an array of symbols.
182
225
  #
183
226
  # DB.tables # => [:albums, :artists]
@@ -189,7 +232,7 @@ module Sequel
189
232
  # either all statements are successful or none of the statements are
190
233
  # successful. Note that MySQL MyISAM tabels do not support transactions.
191
234
  #
192
- # The following options are respected:
235
+ # The following general options are respected:
193
236
  #
194
237
  # :isolation :: The transaction isolation level to use for this transaction,
195
238
  # should be :uncommitted, :committed, :repeatable, or :serializable,
@@ -198,11 +241,22 @@ module Sequel
198
241
  # :prepare :: A string to use as the transaction identifier for a
199
242
  # prepared transaction (two-phase commit), if the database/adapter
200
243
  # supports prepared transactions.
244
+ # :rollback :: Can the set to :reraise to reraise any Sequel::Rollback exceptions
245
+ # raised, or :always to always rollback even if no exceptions occur
246
+ # (useful for testing).
201
247
  # :server :: The server to use for the transaction.
202
248
  # :savepoint :: Whether to create a new savepoint for this transaction,
203
249
  # only respected if the database/adapter supports savepoints. By
204
250
  # default Sequel will reuse an existing transaction, so if you want to
205
251
  # use a savepoint you must use this option.
252
+ #
253
+ # PostgreSQL specific options:
254
+ #
255
+ # :deferrable :: (9.1+) If present, set to DEFERRABLE if true or NOT DEFERRABLE if false.
256
+ # :read_only :: If present, set to READ ONLY if true or READ WRITE if false.
257
+ # :synchronous :: if non-nil, set synchronous_commit
258
+ # appropriately. Valid values true, :on, false, :off, :local (9.1+),
259
+ # and :remote_write (9.2+).
206
260
  def transaction(opts={}, &block)
207
261
  synchronize(opts[:server]) do |conn|
208
262
  return yield(conn) if already_in_transaction?(conn, opts)
@@ -210,47 +264,99 @@ module Sequel
210
264
  end
211
265
  end
212
266
 
267
+ # Return all views in the database as an array of symbols.
268
+ #
269
+ # DB.views # => [:gold_albums, :artists_with_many_albums]
270
+ def views(opts={})
271
+ raise NotImplemented, "#views should be overridden by adapters"
272
+ end
273
+
213
274
  private
214
275
 
276
+ # Should raise an error if the table doesn't not exist,
277
+ # and not raise an error if the table does exist.
278
+ def _table_exists?(ds)
279
+ ds.get(Sequel::NULL)
280
+ end
281
+
215
282
  # Internal generic transaction method. Any exception raised by the given
216
283
  # block will cause the transaction to be rolled back. If the exception is
217
284
  # not a Sequel::Rollback, the error will be reraised. If no exception occurs
218
285
  # inside the block, the transaction is commited.
219
286
  def _transaction(conn, opts={})
287
+ rollback = opts[:rollback]
220
288
  begin
221
- add_transaction
222
- t = begin_transaction(conn, opts)
223
- yield(conn)
289
+ add_transaction(conn, opts)
290
+ begin_transaction(conn, opts)
291
+ if rollback == :always
292
+ begin
293
+ yield(conn)
294
+ rescue Exception => e1
295
+ raise e1
296
+ ensure
297
+ raise ::Sequel::Rollback unless e1
298
+ end
299
+ else
300
+ yield(conn)
301
+ end
224
302
  rescue Exception => e
225
- rollback_transaction(t, opts) if t
226
- transaction_error(e)
303
+ begin
304
+ rollback_transaction(conn, opts)
305
+ rescue Exception => e3
306
+ raise_error(e3, :classes=>database_error_classes, :conn=>conn)
307
+ end
308
+ transaction_error(e, :conn=>conn, :rollback=>rollback)
227
309
  ensure
228
310
  begin
229
- commit_transaction(t, opts) unless e
230
- rescue Exception => e
231
- raise_error(e, :classes=>database_error_classes)
311
+ committed = commit_or_rollback_transaction(e, conn, opts)
312
+ rescue Exception => e2
313
+ raise_error(e2, :classes=>database_error_classes, :conn=>conn)
232
314
  ensure
233
- remove_transaction(t)
315
+ remove_transaction(conn, committed)
234
316
  end
235
317
  end
236
318
  end
237
-
319
+
320
+ # Synchronize access to the current transactions, returning the hash
321
+ # of options for the current transaction (if any)
322
+ def _trans(conn)
323
+ Sequel.synchronize{@transactions[conn]}
324
+ end
325
+
238
326
  # Add the current thread to the list of active transactions
239
- def add_transaction
240
- th = Thread.current
327
+ def add_transaction(conn, opts)
241
328
  if supports_savepoints?
242
- unless @transactions.include?(th)
243
- th[:sequel_transaction_depth] = 0
244
- @transactions << th
329
+ unless _trans(conn)
330
+ if (prep = opts[:prepare]) && supports_prepared_transactions?
331
+ Sequel.synchronize{@transactions[conn] = {:savepoint_level=>0, :prepare=>prep}}
332
+ else
333
+ Sequel.synchronize{@transactions[conn] = {:savepoint_level=>0}}
334
+ end
245
335
  end
336
+ elsif (prep = opts[:prepare]) && supports_prepared_transactions?
337
+ Sequel.synchronize{@transactions[conn] = {:prepare => prep}}
246
338
  else
247
- @transactions << th
339
+ Sequel.synchronize{@transactions[conn] = {}}
248
340
  end
249
341
  end
250
342
 
343
+ # Call all stored after_commit blocks for the given transaction
344
+ def after_transaction_commit(conn)
345
+ if ary = _trans(conn)[:after_commit]
346
+ ary.each{|b| b.call}
347
+ end
348
+ end
349
+
350
+ # Call all stored after_rollback blocks for the given transaction
351
+ def after_transaction_rollback(conn)
352
+ if ary = _trans(conn)[:after_rollback]
353
+ ary.each{|b| b.call}
354
+ end
355
+ end
356
+
251
357
  # Whether the current thread/connection is already inside a transaction
252
358
  def already_in_transaction?(conn, opts)
253
- @transactions.include?(Thread.current) && (!supports_savepoints? || !opts[:savepoint])
359
+ _trans(conn) && (!supports_savepoints? || !opts[:savepoint])
254
360
  end
255
361
 
256
362
  # SQL to start a new savepoint
@@ -267,17 +373,16 @@ module Sequel
267
373
  # Start a new database transaction or a new savepoint on the given connection.
268
374
  def begin_transaction(conn, opts={})
269
375
  if supports_savepoints?
270
- th = Thread.current
271
- if (depth = th[:sequel_transaction_depth]) > 0
376
+ th = _trans(conn)
377
+ if (depth = th[:savepoint_level]) > 0
272
378
  log_connection_execute(conn, begin_savepoint_sql(depth))
273
379
  else
274
380
  begin_new_transaction(conn, opts)
275
381
  end
276
- th[:sequel_transaction_depth] += 1
382
+ th[:savepoint_level] += 1
277
383
  else
278
384
  begin_new_transaction(conn, opts)
279
385
  end
280
- conn
281
386
  end
282
387
 
283
388
  # SQL to BEGIN a transaction.
@@ -285,56 +390,102 @@ module Sequel
285
390
  SQL_BEGIN
286
391
  end
287
392
 
393
+ # Whether the type should be treated as a string type when parsing the
394
+ # column schema default value.
395
+ def column_schema_default_string_type?(type)
396
+ COLUMN_SCHEMA_STRING_TYPES.include?(type)
397
+ end
398
+
399
+ # Transform the given normalized default string into a ruby object for the
400
+ # given type.
401
+ def column_schema_default_to_ruby_value(default, type)
402
+ case type
403
+ when :boolean
404
+ case default
405
+ when /[f0]/i
406
+ false
407
+ when /[t1]/i
408
+ true
409
+ end
410
+ when :string, :enum, :set, :interval
411
+ default
412
+ when :blob
413
+ Sequel::SQL::Blob.new(default)
414
+ when :integer
415
+ Integer(default)
416
+ when :float
417
+ Float(default)
418
+ when :date
419
+ Sequel.string_to_date(default)
420
+ when :datetime
421
+ DateTime.parse(default)
422
+ when :time
423
+ Sequel.string_to_time(default)
424
+ when :decimal
425
+ BigDecimal.new(default)
426
+ end
427
+ end
428
+
429
+ # Normalize the default value string for the given type
430
+ # and return the normalized value.
431
+ def column_schema_normalize_default(default, type)
432
+ if column_schema_default_string_type?(type)
433
+ return unless m = STRING_DEFAULT_RE.match(default)
434
+ m[1].gsub("''", "'")
435
+ else
436
+ default
437
+ end
438
+ end
439
+
288
440
  # Convert the given default, which should be a database specific string, into
289
441
  # a ruby object.
290
442
  def column_schema_to_ruby_default(default, type)
291
443
  return if default.nil?
292
- orig_default = default
293
- if database_type == :postgres and m = POSTGRES_DEFAULT_RE.match(default)
294
- default = m[1] || m[2]
295
- end
296
- if database_type == :mssql and m = MSSQL_DEFAULT_RE.match(default)
297
- default = m[1] || m[2]
298
- end
299
- if [:string, :blob, :date, :datetime, :time, :enum].include?(type)
300
- if database_type == :mysql
301
- return if [:date, :datetime, :time].include?(type) && MYSQL_TIMESTAMP_RE.match(default)
302
- orig_default = default = "'#{default.gsub("'", "''").gsub('\\', '\\\\')}'"
444
+ if COLUMN_SCHEMA_DATETIME_TYPES.include?(type)
445
+ if CURRENT_TIMESTAMP_RE.match(default)
446
+ if type == :date
447
+ return Sequel::CURRENT_DATE
448
+ else
449
+ return Sequel::CURRENT_TIMESTAMP
450
+ end
303
451
  end
304
- return unless m = STRING_DEFAULT_RE.match(default)
305
- default = m[1].gsub("''", "'")
306
452
  end
307
- res = begin
308
- case type
309
- when :boolean
310
- case default
311
- when /[f0]/i
453
+ default = column_schema_normalize_default(default, type)
454
+ column_schema_default_to_ruby_value(default, type) rescue nil
455
+ end
456
+
457
+ if (! defined?(RUBY_ENGINE) or RUBY_ENGINE == 'ruby' or RUBY_ENGINE == 'rbx') and RUBY_VERSION < '1.9'
458
+ # Whether to commit the current transaction. On ruby 1.8 and rubinius,
459
+ # Thread.current.status is checked because Thread#kill skips rescue
460
+ # blocks (so exception would be nil), but the transaction should
461
+ # still be rolled back.
462
+ def commit_or_rollback_transaction(exception, conn, opts)
463
+ if exception
464
+ false
465
+ else
466
+ if Thread.current.status == 'aborting'
467
+ rollback_transaction(conn, opts)
312
468
  false
313
- when /[t1]/i
469
+ else
470
+ commit_transaction(conn, opts)
314
471
  true
315
472
  end
316
- when :string, :enum
317
- default
318
- when :blob
319
- Sequel::SQL::Blob.new(default)
320
- when :integer
321
- Integer(default)
322
- when :float
323
- Float(default)
324
- when :date
325
- Sequel.string_to_date(default)
326
- when :datetime
327
- DateTime.parse(default)
328
- when :time
329
- Sequel.string_to_time(default)
330
- when :decimal
331
- BigDecimal.new(default)
332
473
  end
333
- rescue
334
- nil
474
+ end
475
+ else
476
+ # Whether to commit the current transaction. On ruby 1.9 and JRuby,
477
+ # transactions will be committed if Thread#kill is used on an thread
478
+ # that has a transaction open, and there isn't a work around.
479
+ def commit_or_rollback_transaction(exception, conn, opts)
480
+ if exception
481
+ false
482
+ else
483
+ commit_transaction(conn, opts)
484
+ true
485
+ end
335
486
  end
336
487
  end
337
-
488
+
338
489
  # SQL to commit a savepoint
339
490
  def commit_savepoint_sql(depth)
340
491
  SQL_RELEASE_SAVEPOINT % depth
@@ -343,7 +494,7 @@ module Sequel
343
494
  # Commit the active transaction on the connection
344
495
  def commit_transaction(conn, opts={})
345
496
  if supports_savepoints?
346
- depth = Thread.current[:sequel_transaction_depth]
497
+ depth = _trans(conn)[:savepoint_level]
347
498
  log_connection_execute(conn, depth > 1 ? commit_savepoint_sql(depth-1) : commit_transaction_sql)
348
499
  else
349
500
  log_connection_execute(conn, commit_transaction_sql)
@@ -364,8 +515,8 @@ module Sequel
364
515
  # Return a Method object for the dataset's output_identifier_method.
365
516
  # Used in metadata parsing to make sure the returned information is in the
366
517
  # correct format.
367
- def input_identifier_meth
368
- dataset.method(:input_identifier)
518
+ def input_identifier_meth(ds=nil)
519
+ (ds || dataset).method(:input_identifier)
369
520
  end
370
521
 
371
522
  # Return a dataset that uses the default identifier input and output methods
@@ -382,24 +533,28 @@ module Sequel
382
533
  # Return a Method object for the dataset's output_identifier_method.
383
534
  # Used in metadata parsing to make sure the returned information is in the
384
535
  # correct format.
385
- def output_identifier_meth
386
- dataset.method(:output_identifier)
536
+ def output_identifier_meth(ds=nil)
537
+ (ds || dataset).method(:output_identifier)
387
538
  end
388
539
 
389
- # SQL to ROLLBACK a transaction.
390
- def rollback_transaction_sql
391
- SQL_ROLLBACK
392
- end
393
-
394
540
  # Remove the cached schema for the given schema name
395
541
  def remove_cached_schema(table)
396
542
  @schemas.delete(quote_schema_table(table)) if @schemas
397
543
  end
398
544
 
399
545
  # Remove the current thread from the list of active transactions
400
- def remove_transaction(conn)
401
- th = Thread.current
402
- @transactions.delete(th) if !supports_savepoints? || ((th[:sequel_transaction_depth] -= 1) <= 0)
546
+ def remove_transaction(conn, committed)
547
+ if !supports_savepoints? || ((_trans(conn)[:savepoint_level] -= 1) <= 0)
548
+ begin
549
+ if committed
550
+ after_transaction_commit(conn)
551
+ else
552
+ after_transaction_rollback(conn)
553
+ end
554
+ ensure
555
+ Sequel.synchronize{@transactions.delete(conn)}
556
+ end
557
+ end
403
558
  end
404
559
 
405
560
  # SQL to rollback to a savepoint
@@ -410,37 +565,40 @@ module Sequel
410
565
  # Rollback the active transaction on the connection
411
566
  def rollback_transaction(conn, opts={})
412
567
  if supports_savepoints?
413
- depth = Thread.current[:sequel_transaction_depth]
568
+ depth = _trans(conn)[:savepoint_level]
414
569
  log_connection_execute(conn, depth > 1 ? rollback_savepoint_sql(depth-1) : rollback_transaction_sql)
415
570
  else
416
571
  log_connection_execute(conn, rollback_transaction_sql)
417
572
  end
418
573
  end
419
574
 
575
+ # SQL to ROLLBACK a transaction.
576
+ def rollback_transaction_sql
577
+ SQL_ROLLBACK
578
+ end
579
+
420
580
  # Match the database's column type to a ruby type via a
421
581
  # regular expression, and return the ruby type as a symbol
422
582
  # such as :integer or :string.
423
583
  def schema_column_type(db_type)
424
584
  case db_type
425
- when /\Ainterval\z/io
426
- :interval
427
585
  when /\A(character( varying)?|n?(var)?char|n?text)/io
428
586
  :string
429
587
  when /\A(int(eger)?|(big|small|tiny)int)/io
430
588
  :integer
431
589
  when /\Adate\z/io
432
590
  :date
433
- when /\A((small)?datetime|timestamp( with(out)? time zone)?)\z/io
591
+ when /\A((small)?datetime|timestamp( with(out)? time zone)?)(\(\d+\))?\z/io
434
592
  :datetime
435
593
  when /\Atime( with(out)? time zone)?\z/io
436
594
  :time
437
- when /\A(boolean|bit)\z/io
595
+ when /\A(bool(ean)?)\z/io
438
596
  :boolean
439
- when /\A(real|float|double( precision)?)\z/io
597
+ when /\A(real|float|double( precision)?|double\(\d+,\d+\)( unsigned)?)\z/io
440
598
  :float
441
- when /\A(?:(?:(?:num(?:ber|eric)?|decimal)(?:\(\d+,\s*(\d+)\))?)|(?:small)?money)\z/io
442
- $1 && $1 == '0' ? :integer : :decimal
443
- when /bytea|blob|image|(var)?binary/io
599
+ when /\A(?:(?:(?:num(?:ber|eric)?|decimal)(?:\(\d+,\s*(\d+|false|true)\))?)|(?:small)?money)\z/io
600
+ $1 && ['0', 'false'].include?($1) ? :integer : :decimal
601
+ when /bytea|[bc]lob|image|(var)?binary/io
444
602
  :blob
445
603
  when /\Aenum/io
446
604
  :enum
@@ -460,8 +618,12 @@ module Sequel
460
618
  end
461
619
 
462
620
  # Raise a database error unless the exception is an Rollback.
463
- def transaction_error(e)
464
- raise_error(e, :classes=>database_error_classes) unless e.is_a?(Rollback)
621
+ def transaction_error(e, opts={})
622
+ if e.is_a?(Rollback)
623
+ raise e if opts[:rollback] == :reraise
624
+ else
625
+ raise_error(e, opts.merge(:classes=>database_error_classes))
626
+ end
465
627
  end
466
628
  end
467
629
  end