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