sequel 4.36.0 → 5.61.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 (760) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG +548 -5749
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +265 -159
  5. data/bin/sequel +34 -12
  6. data/doc/advanced_associations.rdoc +228 -187
  7. data/doc/association_basics.rdoc +281 -291
  8. data/doc/bin_sequel.rdoc +5 -3
  9. data/doc/cheat_sheet.rdoc +86 -51
  10. data/doc/code_order.rdoc +25 -19
  11. data/doc/core_extensions.rdoc +104 -63
  12. data/doc/dataset_basics.rdoc +12 -21
  13. data/doc/dataset_filtering.rdoc +99 -86
  14. data/doc/extensions.rdoc +3 -10
  15. data/doc/fork_safety.rdoc +84 -0
  16. data/doc/mass_assignment.rdoc +74 -31
  17. data/doc/migration.rdoc +59 -51
  18. data/doc/model_dataset_method_design.rdoc +129 -0
  19. data/doc/model_hooks.rdoc +15 -25
  20. data/doc/model_plugins.rdoc +12 -12
  21. data/doc/mssql_stored_procedures.rdoc +3 -3
  22. data/doc/object_model.rdoc +58 -68
  23. data/doc/opening_databases.rdoc +85 -95
  24. data/doc/postgresql.rdoc +263 -38
  25. data/doc/prepared_statements.rdoc +29 -24
  26. data/doc/querying.rdoc +189 -167
  27. data/doc/reflection.rdoc +5 -6
  28. data/doc/release_notes/5.0.0.txt +159 -0
  29. data/doc/release_notes/5.1.0.txt +31 -0
  30. data/doc/release_notes/5.10.0.txt +84 -0
  31. data/doc/release_notes/5.11.0.txt +83 -0
  32. data/doc/release_notes/5.12.0.txt +141 -0
  33. data/doc/release_notes/5.13.0.txt +27 -0
  34. data/doc/release_notes/5.14.0.txt +63 -0
  35. data/doc/release_notes/5.15.0.txt +39 -0
  36. data/doc/release_notes/5.16.0.txt +110 -0
  37. data/doc/release_notes/5.17.0.txt +31 -0
  38. data/doc/release_notes/5.18.0.txt +69 -0
  39. data/doc/release_notes/5.19.0.txt +28 -0
  40. data/doc/release_notes/5.2.0.txt +33 -0
  41. data/doc/release_notes/5.20.0.txt +89 -0
  42. data/doc/release_notes/5.21.0.txt +87 -0
  43. data/doc/release_notes/5.22.0.txt +48 -0
  44. data/doc/release_notes/5.23.0.txt +56 -0
  45. data/doc/release_notes/5.24.0.txt +56 -0
  46. data/doc/release_notes/5.25.0.txt +32 -0
  47. data/doc/release_notes/5.26.0.txt +35 -0
  48. data/doc/release_notes/5.27.0.txt +21 -0
  49. data/doc/release_notes/5.28.0.txt +16 -0
  50. data/doc/release_notes/5.29.0.txt +22 -0
  51. data/doc/release_notes/5.3.0.txt +121 -0
  52. data/doc/release_notes/5.30.0.txt +20 -0
  53. data/doc/release_notes/5.31.0.txt +148 -0
  54. data/doc/release_notes/5.32.0.txt +46 -0
  55. data/doc/release_notes/5.33.0.txt +24 -0
  56. data/doc/release_notes/5.34.0.txt +40 -0
  57. data/doc/release_notes/5.35.0.txt +56 -0
  58. data/doc/release_notes/5.36.0.txt +60 -0
  59. data/doc/release_notes/5.37.0.txt +30 -0
  60. data/doc/release_notes/5.38.0.txt +28 -0
  61. data/doc/release_notes/5.39.0.txt +19 -0
  62. data/doc/release_notes/5.4.0.txt +80 -0
  63. data/doc/release_notes/5.40.0.txt +40 -0
  64. data/doc/release_notes/5.41.0.txt +25 -0
  65. data/doc/release_notes/5.42.0.txt +136 -0
  66. data/doc/release_notes/5.43.0.txt +98 -0
  67. data/doc/release_notes/5.44.0.txt +32 -0
  68. data/doc/release_notes/5.45.0.txt +34 -0
  69. data/doc/release_notes/5.46.0.txt +87 -0
  70. data/doc/release_notes/5.47.0.txt +59 -0
  71. data/doc/release_notes/5.48.0.txt +14 -0
  72. data/doc/release_notes/5.49.0.txt +59 -0
  73. data/doc/release_notes/5.5.0.txt +61 -0
  74. data/doc/release_notes/5.50.0.txt +78 -0
  75. data/doc/release_notes/5.51.0.txt +47 -0
  76. data/doc/release_notes/5.52.0.txt +87 -0
  77. data/doc/release_notes/5.53.0.txt +23 -0
  78. data/doc/release_notes/5.54.0.txt +27 -0
  79. data/doc/release_notes/5.55.0.txt +21 -0
  80. data/doc/release_notes/5.56.0.txt +51 -0
  81. data/doc/release_notes/5.57.0.txt +23 -0
  82. data/doc/release_notes/5.58.0.txt +31 -0
  83. data/doc/release_notes/5.59.0.txt +73 -0
  84. data/doc/release_notes/5.6.0.txt +31 -0
  85. data/doc/release_notes/5.60.0.txt +22 -0
  86. data/doc/release_notes/5.61.0.txt +43 -0
  87. data/doc/release_notes/5.7.0.txt +108 -0
  88. data/doc/release_notes/5.8.0.txt +170 -0
  89. data/doc/release_notes/5.9.0.txt +99 -0
  90. data/doc/schema_modification.rdoc +95 -75
  91. data/doc/security.rdoc +109 -80
  92. data/doc/sharding.rdoc +74 -47
  93. data/doc/sql.rdoc +147 -122
  94. data/doc/testing.rdoc +43 -20
  95. data/doc/thread_safety.rdoc +2 -4
  96. data/doc/transactions.rdoc +97 -18
  97. data/doc/validations.rdoc +52 -50
  98. data/doc/virtual_rows.rdoc +90 -109
  99. data/lib/sequel/adapters/ado/access.rb +15 -17
  100. data/lib/sequel/adapters/ado/mssql.rb +6 -15
  101. data/lib/sequel/adapters/ado.rb +150 -20
  102. data/lib/sequel/adapters/amalgalite.rb +11 -23
  103. data/lib/sequel/adapters/ibmdb.rb +47 -55
  104. data/lib/sequel/adapters/jdbc/db2.rb +29 -39
  105. data/lib/sequel/adapters/jdbc/derby.rb +58 -54
  106. data/lib/sequel/adapters/jdbc/h2.rb +93 -35
  107. data/lib/sequel/adapters/jdbc/hsqldb.rb +24 -31
  108. data/lib/sequel/adapters/jdbc/jtds.rb +2 -10
  109. data/lib/sequel/adapters/jdbc/mssql.rb +3 -11
  110. data/lib/sequel/adapters/jdbc/mysql.rb +17 -20
  111. data/lib/sequel/adapters/jdbc/oracle.rb +22 -18
  112. data/lib/sequel/adapters/jdbc/postgresql.rb +69 -71
  113. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +11 -23
  114. data/lib/sequel/adapters/jdbc/sqlite.rb +47 -11
  115. data/lib/sequel/adapters/jdbc/sqlserver.rb +34 -9
  116. data/lib/sequel/adapters/jdbc/transactions.rb +22 -38
  117. data/lib/sequel/adapters/jdbc.rb +145 -130
  118. data/lib/sequel/adapters/mock.rb +100 -111
  119. data/lib/sequel/adapters/mysql.rb +114 -122
  120. data/lib/sequel/adapters/mysql2.rb +147 -63
  121. data/lib/sequel/adapters/odbc/db2.rb +1 -1
  122. data/lib/sequel/adapters/odbc/mssql.rb +8 -14
  123. data/lib/sequel/adapters/odbc/oracle.rb +11 -0
  124. data/lib/sequel/adapters/odbc.rb +20 -25
  125. data/lib/sequel/adapters/oracle.rb +50 -56
  126. data/lib/sequel/adapters/postgres.rb +305 -327
  127. data/lib/sequel/adapters/postgresql.rb +1 -1
  128. data/lib/sequel/adapters/shared/access.rb +74 -78
  129. data/lib/sequel/adapters/shared/db2.rb +118 -71
  130. data/lib/sequel/adapters/shared/mssql.rb +301 -220
  131. data/lib/sequel/adapters/shared/mysql.rb +299 -217
  132. data/lib/sequel/adapters/shared/oracle.rb +226 -65
  133. data/lib/sequel/adapters/shared/postgres.rb +935 -395
  134. data/lib/sequel/adapters/shared/sqlanywhere.rb +105 -126
  135. data/lib/sequel/adapters/shared/sqlite.rb +447 -173
  136. data/lib/sequel/adapters/sqlanywhere.rb +48 -35
  137. data/lib/sequel/adapters/sqlite.rb +156 -111
  138. data/lib/sequel/adapters/tinytds.rb +30 -38
  139. data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
  140. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +3 -6
  141. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +2 -2
  142. data/lib/sequel/adapters/utils/mysql_mysql2.rb +87 -0
  143. data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +56 -0
  144. data/lib/sequel/adapters/utils/replace.rb +1 -4
  145. data/lib/sequel/adapters/utils/stored_procedures.rb +7 -22
  146. data/lib/sequel/adapters/utils/unmodified_identifiers.rb +28 -0
  147. data/lib/sequel/ast_transformer.rb +17 -89
  148. data/lib/sequel/connection_pool/sharded_single.rb +18 -15
  149. data/lib/sequel/connection_pool/sharded_threaded.rb +130 -111
  150. data/lib/sequel/connection_pool/single.rb +18 -13
  151. data/lib/sequel/connection_pool/threaded.rb +121 -120
  152. data/lib/sequel/connection_pool.rb +48 -29
  153. data/lib/sequel/core.rb +351 -301
  154. data/lib/sequel/database/connecting.rb +69 -57
  155. data/lib/sequel/database/dataset.rb +13 -5
  156. data/lib/sequel/database/dataset_defaults.rb +18 -102
  157. data/lib/sequel/database/features.rb +18 -4
  158. data/lib/sequel/database/logging.rb +12 -11
  159. data/lib/sequel/database/misc.rb +180 -122
  160. data/lib/sequel/database/query.rb +47 -27
  161. data/lib/sequel/database/schema_generator.rb +178 -84
  162. data/lib/sequel/database/schema_methods.rb +172 -97
  163. data/lib/sequel/database/transactions.rb +205 -44
  164. data/lib/sequel/database.rb +17 -2
  165. data/lib/sequel/dataset/actions.rb +339 -155
  166. data/lib/sequel/dataset/dataset_module.rb +46 -0
  167. data/lib/sequel/dataset/features.rb +90 -35
  168. data/lib/sequel/dataset/graph.rb +80 -58
  169. data/lib/sequel/dataset/misc.rb +137 -47
  170. data/lib/sequel/dataset/placeholder_literalizer.rb +63 -25
  171. data/lib/sequel/dataset/prepared_statements.rb +188 -85
  172. data/lib/sequel/dataset/query.rb +530 -222
  173. data/lib/sequel/dataset/sql.rb +590 -368
  174. data/lib/sequel/dataset.rb +26 -16
  175. data/lib/sequel/deprecated.rb +12 -2
  176. data/lib/sequel/exceptions.rb +46 -16
  177. data/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
  178. data/lib/sequel/extensions/_model_pg_row.rb +43 -0
  179. data/lib/sequel/extensions/_pretty_table.rb +2 -5
  180. data/lib/sequel/extensions/any_not_empty.rb +45 -0
  181. data/lib/sequel/extensions/arbitrary_servers.rb +10 -10
  182. data/lib/sequel/extensions/async_thread_pool.rb +438 -0
  183. data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
  184. data/lib/sequel/extensions/blank.rb +8 -0
  185. data/lib/sequel/extensions/caller_logging.rb +79 -0
  186. data/lib/sequel/extensions/columns_introspection.rb +4 -3
  187. data/lib/sequel/extensions/connection_expiration.rb +20 -10
  188. data/lib/sequel/extensions/connection_validator.rb +11 -10
  189. data/lib/sequel/extensions/constant_sql_override.rb +65 -0
  190. data/lib/sequel/extensions/constraint_validations.rb +62 -39
  191. data/lib/sequel/extensions/core_extensions.rb +42 -48
  192. data/lib/sequel/extensions/core_refinements.rb +80 -59
  193. data/lib/sequel/extensions/current_datetime_timestamp.rb +1 -4
  194. data/lib/sequel/extensions/date_arithmetic.rb +98 -39
  195. data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
  196. data/lib/sequel/extensions/datetime_parse_to_time.rb +41 -0
  197. data/lib/sequel/extensions/duplicate_columns_handler.rb +21 -14
  198. data/lib/sequel/extensions/empty_array_consider_nulls.rb +2 -2
  199. data/lib/sequel/extensions/escaped_like.rb +100 -0
  200. data/lib/sequel/extensions/eval_inspect.rb +12 -15
  201. data/lib/sequel/extensions/exclude_or_null.rb +68 -0
  202. data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  203. data/lib/sequel/extensions/freeze_datasets.rb +3 -0
  204. data/lib/sequel/extensions/from_block.rb +1 -34
  205. data/lib/sequel/extensions/graph_each.rb +4 -4
  206. data/lib/sequel/extensions/identifier_mangling.rb +180 -0
  207. data/lib/sequel/extensions/implicit_subquery.rb +48 -0
  208. data/lib/sequel/extensions/index_caching.rb +109 -0
  209. data/lib/sequel/extensions/inflector.rb +13 -5
  210. data/lib/sequel/extensions/integer64.rb +32 -0
  211. data/lib/sequel/extensions/is_distinct_from.rb +141 -0
  212. data/lib/sequel/extensions/looser_typecasting.rb +17 -8
  213. data/lib/sequel/extensions/migration.rb +119 -78
  214. data/lib/sequel/extensions/named_timezones.rb +88 -23
  215. data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -82
  216. data/lib/sequel/extensions/null_dataset.rb +8 -8
  217. data/lib/sequel/extensions/pagination.rb +32 -29
  218. data/lib/sequel/extensions/pg_array.rb +221 -287
  219. data/lib/sequel/extensions/pg_array_ops.rb +17 -9
  220. data/lib/sequel/extensions/pg_enum.rb +63 -23
  221. data/lib/sequel/extensions/pg_extended_date_support.rb +241 -0
  222. data/lib/sequel/extensions/pg_hstore.rb +45 -54
  223. data/lib/sequel/extensions/pg_hstore_ops.rb +58 -6
  224. data/lib/sequel/extensions/pg_inet.rb +31 -12
  225. data/lib/sequel/extensions/pg_inet_ops.rb +2 -2
  226. data/lib/sequel/extensions/pg_interval.rb +56 -29
  227. data/lib/sequel/extensions/pg_json.rb +417 -140
  228. data/lib/sequel/extensions/pg_json_ops.rb +270 -18
  229. data/lib/sequel/extensions/pg_loose_count.rb +4 -2
  230. data/lib/sequel/extensions/pg_multirange.rb +372 -0
  231. data/lib/sequel/extensions/pg_range.rb +131 -191
  232. data/lib/sequel/extensions/pg_range_ops.rb +42 -13
  233. data/lib/sequel/extensions/pg_row.rb +48 -81
  234. data/lib/sequel/extensions/pg_row_ops.rb +33 -14
  235. data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -2
  236. data/lib/sequel/extensions/pg_timestamptz.rb +28 -0
  237. data/lib/sequel/extensions/query.rb +9 -7
  238. data/lib/sequel/extensions/round_timestamps.rb +0 -6
  239. data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  240. data/lib/sequel/extensions/s.rb +60 -0
  241. data/lib/sequel/extensions/schema_caching.rb +10 -1
  242. data/lib/sequel/extensions/schema_dumper.rb +71 -48
  243. data/lib/sequel/extensions/select_remove.rb +4 -4
  244. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +85 -0
  245. data/lib/sequel/extensions/server_block.rb +51 -27
  246. data/lib/sequel/extensions/split_array_nil.rb +4 -4
  247. data/lib/sequel/extensions/sql_comments.rb +119 -7
  248. data/lib/sequel/extensions/sql_expr.rb +2 -1
  249. data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
  250. data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
  251. data/lib/sequel/extensions/string_agg.rb +11 -8
  252. data/lib/sequel/extensions/string_date_time.rb +19 -23
  253. data/lib/sequel/extensions/symbol_aref.rb +55 -0
  254. data/lib/sequel/extensions/symbol_aref_refinement.rb +43 -0
  255. data/lib/sequel/extensions/symbol_as.rb +23 -0
  256. data/lib/sequel/extensions/symbol_as_refinement.rb +37 -0
  257. data/lib/sequel/extensions/synchronize_sql.rb +45 -0
  258. data/lib/sequel/extensions/to_dot.rb +10 -4
  259. data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
  260. data/lib/sequel/model/associations.rb +1006 -284
  261. data/lib/sequel/model/base.rb +560 -805
  262. data/lib/sequel/model/dataset_module.rb +11 -10
  263. data/lib/sequel/model/default_inflections.rb +1 -1
  264. data/lib/sequel/model/errors.rb +10 -3
  265. data/lib/sequel/model/exceptions.rb +8 -10
  266. data/lib/sequel/model/inflections.rb +7 -20
  267. data/lib/sequel/model/plugins.rb +114 -0
  268. data/lib/sequel/model.rb +32 -82
  269. data/lib/sequel/plugins/active_model.rb +30 -14
  270. data/lib/sequel/plugins/after_initialize.rb +1 -1
  271. data/lib/sequel/plugins/association_dependencies.rb +25 -18
  272. data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
  273. data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
  274. data/lib/sequel/plugins/association_pks.rb +147 -70
  275. data/lib/sequel/plugins/association_proxies.rb +33 -9
  276. data/lib/sequel/plugins/async_thread_pool.rb +39 -0
  277. data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
  278. data/lib/sequel/plugins/auto_validations.rb +95 -28
  279. data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
  280. data/lib/sequel/plugins/before_after_save.rb +0 -42
  281. data/lib/sequel/plugins/blacklist_security.rb +21 -12
  282. data/lib/sequel/plugins/boolean_readers.rb +5 -5
  283. data/lib/sequel/plugins/boolean_subsets.rb +13 -8
  284. data/lib/sequel/plugins/caching.rb +25 -16
  285. data/lib/sequel/plugins/class_table_inheritance.rb +179 -100
  286. data/lib/sequel/plugins/column_conflicts.rb +16 -3
  287. data/lib/sequel/plugins/column_encryption.rb +728 -0
  288. data/lib/sequel/plugins/column_select.rb +7 -5
  289. data/lib/sequel/plugins/columns_updated.rb +42 -0
  290. data/lib/sequel/plugins/composition.rb +42 -26
  291. data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
  292. data/lib/sequel/plugins/constraint_validations.rb +20 -14
  293. data/lib/sequel/plugins/csv_serializer.rb +56 -35
  294. data/lib/sequel/plugins/dataset_associations.rb +40 -17
  295. data/lib/sequel/plugins/def_dataset_method.rb +90 -0
  296. data/lib/sequel/plugins/defaults_setter.rb +65 -10
  297. data/lib/sequel/plugins/delay_add_association.rb +1 -1
  298. data/lib/sequel/plugins/dirty.rb +62 -24
  299. data/lib/sequel/plugins/eager_each.rb +3 -3
  300. data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
  301. data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
  302. data/lib/sequel/plugins/enum.rb +124 -0
  303. data/lib/sequel/plugins/error_splitter.rb +17 -12
  304. data/lib/sequel/plugins/finder.rb +246 -0
  305. data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
  306. data/lib/sequel/plugins/force_encoding.rb +7 -12
  307. data/lib/sequel/plugins/hook_class_methods.rb +37 -54
  308. data/lib/sequel/plugins/input_transformer.rb +18 -10
  309. data/lib/sequel/plugins/insert_conflict.rb +76 -0
  310. data/lib/sequel/plugins/insert_returning_select.rb +2 -2
  311. data/lib/sequel/plugins/instance_filters.rb +10 -8
  312. data/lib/sequel/plugins/instance_hooks.rb +34 -17
  313. data/lib/sequel/plugins/instance_specific_default.rb +113 -0
  314. data/lib/sequel/plugins/inverted_subsets.rb +22 -13
  315. data/lib/sequel/plugins/json_serializer.rb +124 -64
  316. data/lib/sequel/plugins/lazy_attributes.rb +21 -14
  317. data/lib/sequel/plugins/list.rb +35 -21
  318. data/lib/sequel/plugins/many_through_many.rb +134 -21
  319. data/lib/sequel/plugins/modification_detection.rb +15 -5
  320. data/lib/sequel/plugins/mssql_optimistic_locking.rb +6 -5
  321. data/lib/sequel/plugins/nested_attributes.rb +61 -31
  322. data/lib/sequel/plugins/optimistic_locking.rb +3 -3
  323. data/lib/sequel/plugins/pg_array_associations.rb +103 -53
  324. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +350 -0
  325. data/lib/sequel/plugins/pg_row.rb +5 -51
  326. data/lib/sequel/plugins/prepared_statements.rb +60 -72
  327. data/lib/sequel/plugins/prepared_statements_safe.rb +9 -4
  328. data/lib/sequel/plugins/rcte_tree.rb +68 -82
  329. data/lib/sequel/plugins/require_valid_schema.rb +67 -0
  330. data/lib/sequel/plugins/serialization.rb +43 -46
  331. data/lib/sequel/plugins/serialization_modification_detection.rb +3 -2
  332. data/lib/sequel/plugins/sharding.rb +15 -10
  333. data/lib/sequel/plugins/single_table_inheritance.rb +67 -28
  334. data/lib/sequel/plugins/skip_create_refresh.rb +3 -3
  335. data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
  336. data/lib/sequel/plugins/split_values.rb +11 -6
  337. data/lib/sequel/plugins/sql_comments.rb +189 -0
  338. data/lib/sequel/plugins/static_cache.rb +77 -53
  339. data/lib/sequel/plugins/static_cache_cache.rb +53 -0
  340. data/lib/sequel/plugins/string_stripper.rb +3 -3
  341. data/lib/sequel/plugins/subclasses.rb +43 -10
  342. data/lib/sequel/plugins/subset_conditions.rb +15 -5
  343. data/lib/sequel/plugins/table_select.rb +2 -2
  344. data/lib/sequel/plugins/tactical_eager_loading.rb +96 -12
  345. data/lib/sequel/plugins/throw_failures.rb +110 -0
  346. data/lib/sequel/plugins/timestamps.rb +20 -8
  347. data/lib/sequel/plugins/touch.rb +19 -8
  348. data/lib/sequel/plugins/tree.rb +62 -32
  349. data/lib/sequel/plugins/typecast_on_load.rb +12 -4
  350. data/lib/sequel/plugins/unlimited_update.rb +1 -7
  351. data/lib/sequel/plugins/unused_associations.rb +521 -0
  352. data/lib/sequel/plugins/update_or_create.rb +4 -4
  353. data/lib/sequel/plugins/update_primary_key.rb +1 -1
  354. data/lib/sequel/plugins/update_refresh.rb +26 -15
  355. data/lib/sequel/plugins/uuid.rb +7 -11
  356. data/lib/sequel/plugins/validate_associated.rb +18 -0
  357. data/lib/sequel/plugins/validation_class_methods.rb +38 -19
  358. data/lib/sequel/plugins/validation_contexts.rb +49 -0
  359. data/lib/sequel/plugins/validation_helpers.rb +57 -41
  360. data/lib/sequel/plugins/whitelist_security.rb +122 -0
  361. data/lib/sequel/plugins/xml_serializer.rb +30 -31
  362. data/lib/sequel/sql.rb +471 -331
  363. data/lib/sequel/timezones.rb +78 -47
  364. data/lib/sequel/version.rb +7 -2
  365. data/lib/sequel.rb +1 -1
  366. metadata +217 -521
  367. data/Rakefile +0 -164
  368. data/doc/active_record.rdoc +0 -928
  369. data/doc/release_notes/1.0.txt +0 -38
  370. data/doc/release_notes/1.1.txt +0 -143
  371. data/doc/release_notes/1.3.txt +0 -101
  372. data/doc/release_notes/1.4.0.txt +0 -53
  373. data/doc/release_notes/1.5.0.txt +0 -155
  374. data/doc/release_notes/2.0.0.txt +0 -298
  375. data/doc/release_notes/2.1.0.txt +0 -271
  376. data/doc/release_notes/2.10.0.txt +0 -328
  377. data/doc/release_notes/2.11.0.txt +0 -215
  378. data/doc/release_notes/2.12.0.txt +0 -534
  379. data/doc/release_notes/2.2.0.txt +0 -253
  380. data/doc/release_notes/2.3.0.txt +0 -88
  381. data/doc/release_notes/2.4.0.txt +0 -106
  382. data/doc/release_notes/2.5.0.txt +0 -137
  383. data/doc/release_notes/2.6.0.txt +0 -157
  384. data/doc/release_notes/2.7.0.txt +0 -166
  385. data/doc/release_notes/2.8.0.txt +0 -171
  386. data/doc/release_notes/2.9.0.txt +0 -97
  387. data/doc/release_notes/3.0.0.txt +0 -221
  388. data/doc/release_notes/3.1.0.txt +0 -406
  389. data/doc/release_notes/3.10.0.txt +0 -286
  390. data/doc/release_notes/3.11.0.txt +0 -254
  391. data/doc/release_notes/3.12.0.txt +0 -304
  392. data/doc/release_notes/3.13.0.txt +0 -210
  393. data/doc/release_notes/3.14.0.txt +0 -118
  394. data/doc/release_notes/3.15.0.txt +0 -78
  395. data/doc/release_notes/3.16.0.txt +0 -45
  396. data/doc/release_notes/3.17.0.txt +0 -58
  397. data/doc/release_notes/3.18.0.txt +0 -120
  398. data/doc/release_notes/3.19.0.txt +0 -67
  399. data/doc/release_notes/3.2.0.txt +0 -268
  400. data/doc/release_notes/3.20.0.txt +0 -41
  401. data/doc/release_notes/3.21.0.txt +0 -87
  402. data/doc/release_notes/3.22.0.txt +0 -39
  403. data/doc/release_notes/3.23.0.txt +0 -172
  404. data/doc/release_notes/3.24.0.txt +0 -420
  405. data/doc/release_notes/3.25.0.txt +0 -88
  406. data/doc/release_notes/3.26.0.txt +0 -88
  407. data/doc/release_notes/3.27.0.txt +0 -82
  408. data/doc/release_notes/3.28.0.txt +0 -304
  409. data/doc/release_notes/3.29.0.txt +0 -459
  410. data/doc/release_notes/3.3.0.txt +0 -192
  411. data/doc/release_notes/3.30.0.txt +0 -135
  412. data/doc/release_notes/3.31.0.txt +0 -146
  413. data/doc/release_notes/3.32.0.txt +0 -202
  414. data/doc/release_notes/3.33.0.txt +0 -157
  415. data/doc/release_notes/3.34.0.txt +0 -671
  416. data/doc/release_notes/3.35.0.txt +0 -144
  417. data/doc/release_notes/3.36.0.txt +0 -245
  418. data/doc/release_notes/3.37.0.txt +0 -338
  419. data/doc/release_notes/3.38.0.txt +0 -234
  420. data/doc/release_notes/3.39.0.txt +0 -237
  421. data/doc/release_notes/3.4.0.txt +0 -325
  422. data/doc/release_notes/3.40.0.txt +0 -73
  423. data/doc/release_notes/3.41.0.txt +0 -155
  424. data/doc/release_notes/3.42.0.txt +0 -74
  425. data/doc/release_notes/3.43.0.txt +0 -105
  426. data/doc/release_notes/3.44.0.txt +0 -152
  427. data/doc/release_notes/3.45.0.txt +0 -179
  428. data/doc/release_notes/3.46.0.txt +0 -122
  429. data/doc/release_notes/3.47.0.txt +0 -270
  430. data/doc/release_notes/3.48.0.txt +0 -477
  431. data/doc/release_notes/3.5.0.txt +0 -510
  432. data/doc/release_notes/3.6.0.txt +0 -366
  433. data/doc/release_notes/3.7.0.txt +0 -179
  434. data/doc/release_notes/3.8.0.txt +0 -151
  435. data/doc/release_notes/3.9.0.txt +0 -233
  436. data/doc/release_notes/4.0.0.txt +0 -262
  437. data/doc/release_notes/4.1.0.txt +0 -85
  438. data/doc/release_notes/4.10.0.txt +0 -226
  439. data/doc/release_notes/4.11.0.txt +0 -147
  440. data/doc/release_notes/4.12.0.txt +0 -105
  441. data/doc/release_notes/4.13.0.txt +0 -169
  442. data/doc/release_notes/4.14.0.txt +0 -68
  443. data/doc/release_notes/4.15.0.txt +0 -56
  444. data/doc/release_notes/4.16.0.txt +0 -36
  445. data/doc/release_notes/4.17.0.txt +0 -38
  446. data/doc/release_notes/4.18.0.txt +0 -36
  447. data/doc/release_notes/4.19.0.txt +0 -45
  448. data/doc/release_notes/4.2.0.txt +0 -129
  449. data/doc/release_notes/4.20.0.txt +0 -79
  450. data/doc/release_notes/4.21.0.txt +0 -94
  451. data/doc/release_notes/4.22.0.txt +0 -72
  452. data/doc/release_notes/4.23.0.txt +0 -65
  453. data/doc/release_notes/4.24.0.txt +0 -99
  454. data/doc/release_notes/4.25.0.txt +0 -181
  455. data/doc/release_notes/4.26.0.txt +0 -44
  456. data/doc/release_notes/4.27.0.txt +0 -78
  457. data/doc/release_notes/4.28.0.txt +0 -57
  458. data/doc/release_notes/4.29.0.txt +0 -41
  459. data/doc/release_notes/4.3.0.txt +0 -40
  460. data/doc/release_notes/4.30.0.txt +0 -37
  461. data/doc/release_notes/4.31.0.txt +0 -57
  462. data/doc/release_notes/4.32.0.txt +0 -132
  463. data/doc/release_notes/4.33.0.txt +0 -88
  464. data/doc/release_notes/4.34.0.txt +0 -86
  465. data/doc/release_notes/4.35.0.txt +0 -130
  466. data/doc/release_notes/4.36.0.txt +0 -116
  467. data/doc/release_notes/4.4.0.txt +0 -92
  468. data/doc/release_notes/4.5.0.txt +0 -34
  469. data/doc/release_notes/4.6.0.txt +0 -30
  470. data/doc/release_notes/4.7.0.txt +0 -103
  471. data/doc/release_notes/4.8.0.txt +0 -175
  472. data/doc/release_notes/4.9.0.txt +0 -190
  473. data/lib/sequel/adapters/cubrid.rb +0 -144
  474. data/lib/sequel/adapters/do/mysql.rb +0 -66
  475. data/lib/sequel/adapters/do/postgres.rb +0 -44
  476. data/lib/sequel/adapters/do/sqlite3.rb +0 -42
  477. data/lib/sequel/adapters/do.rb +0 -158
  478. data/lib/sequel/adapters/jdbc/as400.rb +0 -84
  479. data/lib/sequel/adapters/jdbc/cubrid.rb +0 -64
  480. data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -36
  481. data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -33
  482. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -33
  483. data/lib/sequel/adapters/odbc/progress.rb +0 -10
  484. data/lib/sequel/adapters/shared/cubrid.rb +0 -245
  485. data/lib/sequel/adapters/shared/firebird.rb +0 -247
  486. data/lib/sequel/adapters/shared/informix.rb +0 -54
  487. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +0 -152
  488. data/lib/sequel/adapters/shared/progress.rb +0 -40
  489. data/lib/sequel/adapters/swift/mysql.rb +0 -49
  490. data/lib/sequel/adapters/swift/postgres.rb +0 -47
  491. data/lib/sequel/adapters/swift/sqlite.rb +0 -49
  492. data/lib/sequel/adapters/swift.rb +0 -160
  493. data/lib/sequel/adapters/utils/pg_types.rb +0 -70
  494. data/lib/sequel/dataset/mutation.rb +0 -111
  495. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -5
  496. data/lib/sequel/extensions/filter_having.rb +0 -63
  497. data/lib/sequel/extensions/hash_aliases.rb +0 -49
  498. data/lib/sequel/extensions/meta_def.rb +0 -35
  499. data/lib/sequel/extensions/query_literals.rb +0 -84
  500. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -24
  501. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -122
  502. data/lib/sequel/extensions/set_overrides.rb +0 -76
  503. data/lib/sequel/no_core_ext.rb +0 -3
  504. data/lib/sequel/plugins/association_autoreloading.rb +0 -9
  505. data/lib/sequel/plugins/identifier_columns.rb +0 -47
  506. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -9
  507. data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -81
  508. data/lib/sequel/plugins/prepared_statements_associations.rb +0 -119
  509. data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -61
  510. data/lib/sequel/plugins/schema.rb +0 -82
  511. data/lib/sequel/plugins/scissors.rb +0 -35
  512. data/spec/adapter_spec.rb +0 -4
  513. data/spec/adapters/db2_spec.rb +0 -160
  514. data/spec/adapters/firebird_spec.rb +0 -411
  515. data/spec/adapters/informix_spec.rb +0 -100
  516. data/spec/adapters/mssql_spec.rb +0 -733
  517. data/spec/adapters/mysql_spec.rb +0 -1319
  518. data/spec/adapters/oracle_spec.rb +0 -313
  519. data/spec/adapters/postgres_spec.rb +0 -3790
  520. data/spec/adapters/spec_helper.rb +0 -49
  521. data/spec/adapters/sqlanywhere_spec.rb +0 -170
  522. data/spec/adapters/sqlite_spec.rb +0 -688
  523. data/spec/bin_spec.rb +0 -258
  524. data/spec/core/connection_pool_spec.rb +0 -1045
  525. data/spec/core/database_spec.rb +0 -2636
  526. data/spec/core/dataset_spec.rb +0 -5175
  527. data/spec/core/deprecated_spec.rb +0 -70
  528. data/spec/core/expression_filters_spec.rb +0 -1247
  529. data/spec/core/mock_adapter_spec.rb +0 -464
  530. data/spec/core/object_graph_spec.rb +0 -303
  531. data/spec/core/placeholder_literalizer_spec.rb +0 -163
  532. data/spec/core/schema_generator_spec.rb +0 -203
  533. data/spec/core/schema_spec.rb +0 -1676
  534. data/spec/core/spec_helper.rb +0 -34
  535. data/spec/core/version_spec.rb +0 -7
  536. data/spec/core_extensions_spec.rb +0 -699
  537. data/spec/core_model_spec.rb +0 -2
  538. data/spec/core_spec.rb +0 -1
  539. data/spec/extensions/accessed_columns_spec.rb +0 -51
  540. data/spec/extensions/active_model_spec.rb +0 -85
  541. data/spec/extensions/after_initialize_spec.rb +0 -24
  542. data/spec/extensions/arbitrary_servers_spec.rb +0 -109
  543. data/spec/extensions/association_dependencies_spec.rb +0 -117
  544. data/spec/extensions/association_pks_spec.rb +0 -405
  545. data/spec/extensions/association_proxies_spec.rb +0 -86
  546. data/spec/extensions/auto_validations_spec.rb +0 -192
  547. data/spec/extensions/before_after_save_spec.rb +0 -40
  548. data/spec/extensions/blacklist_security_spec.rb +0 -88
  549. data/spec/extensions/blank_spec.rb +0 -69
  550. data/spec/extensions/boolean_readers_spec.rb +0 -93
  551. data/spec/extensions/boolean_subsets_spec.rb +0 -47
  552. data/spec/extensions/caching_spec.rb +0 -270
  553. data/spec/extensions/class_table_inheritance_spec.rb +0 -444
  554. data/spec/extensions/column_conflicts_spec.rb +0 -60
  555. data/spec/extensions/column_select_spec.rb +0 -108
  556. data/spec/extensions/columns_introspection_spec.rb +0 -91
  557. data/spec/extensions/composition_spec.rb +0 -242
  558. data/spec/extensions/connection_expiration_spec.rb +0 -121
  559. data/spec/extensions/connection_validator_spec.rb +0 -127
  560. data/spec/extensions/constraint_validations_plugin_spec.rb +0 -288
  561. data/spec/extensions/constraint_validations_spec.rb +0 -389
  562. data/spec/extensions/core_refinements_spec.rb +0 -519
  563. data/spec/extensions/csv_serializer_spec.rb +0 -180
  564. data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
  565. data/spec/extensions/dataset_associations_spec.rb +0 -343
  566. data/spec/extensions/dataset_source_alias_spec.rb +0 -51
  567. data/spec/extensions/date_arithmetic_spec.rb +0 -167
  568. data/spec/extensions/defaults_setter_spec.rb +0 -102
  569. data/spec/extensions/delay_add_association_spec.rb +0 -74
  570. data/spec/extensions/dirty_spec.rb +0 -180
  571. data/spec/extensions/duplicate_columns_handler_spec.rb +0 -110
  572. data/spec/extensions/eager_each_spec.rb +0 -66
  573. data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
  574. data/spec/extensions/error_splitter_spec.rb +0 -18
  575. data/spec/extensions/error_sql_spec.rb +0 -20
  576. data/spec/extensions/eval_inspect_spec.rb +0 -73
  577. data/spec/extensions/filter_having_spec.rb +0 -40
  578. data/spec/extensions/force_encoding_spec.rb +0 -114
  579. data/spec/extensions/from_block_spec.rb +0 -21
  580. data/spec/extensions/graph_each_spec.rb +0 -119
  581. data/spec/extensions/hash_aliases_spec.rb +0 -24
  582. data/spec/extensions/hook_class_methods_spec.rb +0 -429
  583. data/spec/extensions/identifier_columns_spec.rb +0 -17
  584. data/spec/extensions/inflector_spec.rb +0 -183
  585. data/spec/extensions/input_transformer_spec.rb +0 -54
  586. data/spec/extensions/insert_returning_select_spec.rb +0 -46
  587. data/spec/extensions/instance_filters_spec.rb +0 -79
  588. data/spec/extensions/instance_hooks_spec.rb +0 -276
  589. data/spec/extensions/inverted_subsets_spec.rb +0 -33
  590. data/spec/extensions/json_serializer_spec.rb +0 -304
  591. data/spec/extensions/lazy_attributes_spec.rb +0 -170
  592. data/spec/extensions/list_spec.rb +0 -278
  593. data/spec/extensions/looser_typecasting_spec.rb +0 -43
  594. data/spec/extensions/many_through_many_spec.rb +0 -2172
  595. data/spec/extensions/meta_def_spec.rb +0 -21
  596. data/spec/extensions/migration_spec.rb +0 -728
  597. data/spec/extensions/modification_detection_spec.rb +0 -80
  598. data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -91
  599. data/spec/extensions/named_timezones_spec.rb +0 -108
  600. data/spec/extensions/nested_attributes_spec.rb +0 -697
  601. data/spec/extensions/no_auto_literal_strings_spec.rb +0 -65
  602. data/spec/extensions/null_dataset_spec.rb +0 -85
  603. data/spec/extensions/optimistic_locking_spec.rb +0 -128
  604. data/spec/extensions/pagination_spec.rb +0 -118
  605. data/spec/extensions/pg_array_associations_spec.rb +0 -736
  606. data/spec/extensions/pg_array_ops_spec.rb +0 -143
  607. data/spec/extensions/pg_array_spec.rb +0 -390
  608. data/spec/extensions/pg_enum_spec.rb +0 -92
  609. data/spec/extensions/pg_hstore_ops_spec.rb +0 -236
  610. data/spec/extensions/pg_hstore_spec.rb +0 -206
  611. data/spec/extensions/pg_inet_ops_spec.rb +0 -101
  612. data/spec/extensions/pg_inet_spec.rb +0 -52
  613. data/spec/extensions/pg_interval_spec.rb +0 -76
  614. data/spec/extensions/pg_json_ops_spec.rb +0 -275
  615. data/spec/extensions/pg_json_spec.rb +0 -218
  616. data/spec/extensions/pg_loose_count_spec.rb +0 -17
  617. data/spec/extensions/pg_range_ops_spec.rb +0 -58
  618. data/spec/extensions/pg_range_spec.rb +0 -473
  619. data/spec/extensions/pg_row_ops_spec.rb +0 -60
  620. data/spec/extensions/pg_row_plugin_spec.rb +0 -62
  621. data/spec/extensions/pg_row_spec.rb +0 -360
  622. data/spec/extensions/pg_static_cache_updater_spec.rb +0 -92
  623. data/spec/extensions/pg_typecast_on_load_spec.rb +0 -63
  624. data/spec/extensions/prepared_statements_associations_spec.rb +0 -159
  625. data/spec/extensions/prepared_statements_safe_spec.rb +0 -61
  626. data/spec/extensions/prepared_statements_spec.rb +0 -103
  627. data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -31
  628. data/spec/extensions/pretty_table_spec.rb +0 -92
  629. data/spec/extensions/query_literals_spec.rb +0 -183
  630. data/spec/extensions/query_spec.rb +0 -102
  631. data/spec/extensions/rcte_tree_spec.rb +0 -392
  632. data/spec/extensions/round_timestamps_spec.rb +0 -43
  633. data/spec/extensions/schema_caching_spec.rb +0 -41
  634. data/spec/extensions/schema_dumper_spec.rb +0 -814
  635. data/spec/extensions/schema_spec.rb +0 -117
  636. data/spec/extensions/scissors_spec.rb +0 -26
  637. data/spec/extensions/select_remove_spec.rb +0 -38
  638. data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -101
  639. data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
  640. data/spec/extensions/serialization_spec.rb +0 -362
  641. data/spec/extensions/server_block_spec.rb +0 -90
  642. data/spec/extensions/server_logging_spec.rb +0 -45
  643. data/spec/extensions/set_overrides_spec.rb +0 -61
  644. data/spec/extensions/sharding_spec.rb +0 -198
  645. data/spec/extensions/shared_caching_spec.rb +0 -175
  646. data/spec/extensions/single_table_inheritance_spec.rb +0 -297
  647. data/spec/extensions/singular_table_names_spec.rb +0 -22
  648. data/spec/extensions/skip_create_refresh_spec.rb +0 -17
  649. data/spec/extensions/spec_helper.rb +0 -71
  650. data/spec/extensions/split_array_nil_spec.rb +0 -24
  651. data/spec/extensions/split_values_spec.rb +0 -22
  652. data/spec/extensions/sql_comments_spec.rb +0 -27
  653. data/spec/extensions/sql_expr_spec.rb +0 -60
  654. data/spec/extensions/static_cache_spec.rb +0 -361
  655. data/spec/extensions/string_agg_spec.rb +0 -85
  656. data/spec/extensions/string_date_time_spec.rb +0 -95
  657. data/spec/extensions/string_stripper_spec.rb +0 -68
  658. data/spec/extensions/subclasses_spec.rb +0 -66
  659. data/spec/extensions/subset_conditions_spec.rb +0 -38
  660. data/spec/extensions/table_select_spec.rb +0 -71
  661. data/spec/extensions/tactical_eager_loading_spec.rb +0 -136
  662. data/spec/extensions/thread_local_timezones_spec.rb +0 -67
  663. data/spec/extensions/timestamps_spec.rb +0 -175
  664. data/spec/extensions/to_dot_spec.rb +0 -154
  665. data/spec/extensions/touch_spec.rb +0 -203
  666. data/spec/extensions/tree_spec.rb +0 -274
  667. data/spec/extensions/typecast_on_load_spec.rb +0 -80
  668. data/spec/extensions/unlimited_update_spec.rb +0 -20
  669. data/spec/extensions/update_or_create_spec.rb +0 -87
  670. data/spec/extensions/update_primary_key_spec.rb +0 -100
  671. data/spec/extensions/update_refresh_spec.rb +0 -53
  672. data/spec/extensions/uuid_spec.rb +0 -106
  673. data/spec/extensions/validate_associated_spec.rb +0 -52
  674. data/spec/extensions/validation_class_methods_spec.rb +0 -1027
  675. data/spec/extensions/validation_helpers_spec.rb +0 -554
  676. data/spec/extensions/xml_serializer_spec.rb +0 -207
  677. data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
  678. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
  679. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  680. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  681. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
  682. data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
  683. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
  684. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
  685. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
  686. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
  687. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
  688. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
  689. data/spec/files/double_migration/001_create_sessions.rb +0 -9
  690. data/spec/files/double_migration/002_create_nodes.rb +0 -19
  691. data/spec/files/double_migration/003_3_create_users.rb +0 -4
  692. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
  693. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
  694. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  695. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
  696. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
  697. data/spec/files/empty_migration/001_create_sessions.rb +0 -9
  698. data/spec/files/empty_migration/002_create_nodes.rb +0 -0
  699. data/spec/files/empty_migration/003_3_create_users.rb +0 -4
  700. data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
  701. data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
  702. data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
  703. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  704. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
  705. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  706. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
  707. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  708. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
  709. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
  710. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  711. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  712. data/spec/files/reversible_migrations/001_reversible.rb +0 -5
  713. data/spec/files/reversible_migrations/002_reversible.rb +0 -5
  714. data/spec/files/reversible_migrations/003_reversible.rb +0 -5
  715. data/spec/files/reversible_migrations/004_reversible.rb +0 -5
  716. data/spec/files/reversible_migrations/005_reversible.rb +0 -10
  717. data/spec/files/reversible_migrations/006_reversible.rb +0 -10
  718. data/spec/files/reversible_migrations/007_reversible.rb +0 -10
  719. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
  720. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
  721. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
  722. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
  723. data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
  724. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
  725. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
  726. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
  727. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
  728. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
  729. data/spec/guards_helper.rb +0 -55
  730. data/spec/integration/associations_test.rb +0 -2506
  731. data/spec/integration/database_test.rb +0 -113
  732. data/spec/integration/dataset_test.rb +0 -1858
  733. data/spec/integration/eager_loader_test.rb +0 -687
  734. data/spec/integration/migrator_test.rb +0 -262
  735. data/spec/integration/model_test.rb +0 -230
  736. data/spec/integration/plugin_test.rb +0 -2297
  737. data/spec/integration/prepared_statement_test.rb +0 -467
  738. data/spec/integration/schema_test.rb +0 -815
  739. data/spec/integration/spec_helper.rb +0 -56
  740. data/spec/integration/timezone_test.rb +0 -86
  741. data/spec/integration/transaction_test.rb +0 -406
  742. data/spec/integration/type_test.rb +0 -133
  743. data/spec/model/association_reflection_spec.rb +0 -565
  744. data/spec/model/associations_spec.rb +0 -4589
  745. data/spec/model/base_spec.rb +0 -759
  746. data/spec/model/class_dataset_methods_spec.rb +0 -150
  747. data/spec/model/dataset_methods_spec.rb +0 -149
  748. data/spec/model/eager_loading_spec.rb +0 -2197
  749. data/spec/model/hooks_spec.rb +0 -604
  750. data/spec/model/inflector_spec.rb +0 -26
  751. data/spec/model/model_spec.rb +0 -1097
  752. data/spec/model/plugins_spec.rb +0 -299
  753. data/spec/model/record_spec.rb +0 -2162
  754. data/spec/model/spec_helper.rb +0 -46
  755. data/spec/model/validations_spec.rb +0 -193
  756. data/spec/model_no_assoc_spec.rb +0 -1
  757. data/spec/model_spec.rb +0 -1
  758. data/spec/plugin_spec.rb +0 -1
  759. data/spec/sequel_coverage.rb +0 -15
  760. data/spec/spec_config.rb +0 -10
@@ -1,23 +1,26 @@
1
1
  # frozen-string-literal: true
2
2
 
3
- Sequel.require 'adapters/utils/split_alter_table'
4
- Sequel.require 'adapters/utils/replace'
3
+ require_relative '../utils/replace'
4
+ require_relative '../utils/split_alter_table'
5
+ require_relative '../utils/unmodified_identifiers'
5
6
 
6
7
  module Sequel
7
- Dataset::NON_SQL_OPTIONS << :insert_ignore
8
- Dataset::NON_SQL_OPTIONS << :update_ignore
9
- Dataset::NON_SQL_OPTIONS << :on_duplicate_key_update
10
-
11
8
  module MySQL
12
- @convert_tinyint_to_bool = true
9
+ Sequel::Database.set_shared_adapter_scheme(:mysql, self)
10
+
11
+ def self.mock_adapter_setup(db)
12
+ db.instance_exec do
13
+ @server_version = 50617
14
+ end
15
+ end
13
16
 
14
- class << self
15
- # Sequel converts the column type tinyint(1) to a boolean by default when
16
- # using the native MySQL or Mysql2 adapter. You can turn off the conversion by setting
17
- # this to false. This setting is ignored when connecting to MySQL via the do or jdbc
18
- # adapters, both of which automatically do the conversion.
19
- attr_accessor :convert_tinyint_to_bool
17
+ module DatabaseMethods
18
+ include UnmodifiedIdentifiers::DatabaseMethods
19
+ include Sequel::Database::SplitAlterTable
20
20
 
21
+ CAST_TYPES = {String=>:CHAR, Integer=>:SIGNED, Time=>:DATETIME, DateTime=>:DATETIME, Numeric=>:DECIMAL, BigDecimal=>:DECIMAL, File=>:BINARY}.freeze
22
+ COLUMN_DEFINITION_ORDER = [:generated, :collate, :null, :default, :unique, :primary_key, :auto_increment, :references].freeze
23
+
21
24
  # Set the default charset used for CREATE TABLE. You can pass the
22
25
  # :charset option to create_table to override this setting.
23
26
  attr_accessor :default_charset
@@ -29,34 +32,17 @@ module Sequel
29
32
  # Set the default engine used for CREATE TABLE. You can pass the
30
33
  # :engine option to create_table to override this setting.
31
34
  attr_accessor :default_engine
32
- end
33
35
 
34
- # Methods shared by Database instances that connect to MySQL,
35
- # currently supported by the native and JDBC adapters.
36
- module DatabaseMethods
37
- extend Sequel::Database::ResetIdentifierMangling
38
-
39
- AUTO_INCREMENT = 'AUTO_INCREMENT'.freeze
40
- CAST_TYPES = {String=>:CHAR, Integer=>:SIGNED, Time=>:DATETIME, DateTime=>:DATETIME, Numeric=>:DECIMAL, BigDecimal=>:DECIMAL, File=>:BINARY}
41
- COLUMN_DEFINITION_ORDER = [:collate, :null, :default, :unique, :primary_key, :auto_increment, :references]
42
- PRIMARY = 'PRIMARY'.freeze
43
- MYSQL_TIMESTAMP_RE = /\ACURRENT_(?:DATE|TIMESTAMP)?\z/
44
-
45
- include Sequel::Database::SplitAlterTable
46
-
47
36
  # MySQL's cast rules are restrictive in that you can't just cast to any possible
48
37
  # database type.
49
38
  def cast_type_literal(type)
50
39
  CAST_TYPES[type] || super
51
40
  end
52
41
 
53
- # Commit an existing prepared transaction with the given transaction
54
- # identifier string.
55
42
  def commit_prepared_transaction(transaction_id, opts=OPTS)
56
43
  run("XA COMMIT #{literal(transaction_id)}", opts)
57
44
  end
58
45
 
59
- # MySQL uses the :mysql database type
60
46
  def database_type
61
47
  :mysql
62
48
  end
@@ -68,11 +54,12 @@ module Sequel
68
54
  m = output_identifier_meth
69
55
  im = input_identifier_meth
70
56
  ds = metadata_dataset.
71
- from(:INFORMATION_SCHEMA__KEY_COLUMN_USAGE).
57
+ from(Sequel[:INFORMATION_SCHEMA][:KEY_COLUMN_USAGE]).
72
58
  where(:TABLE_NAME=>im.call(table), :TABLE_SCHEMA=>Sequel.function(:DATABASE)).
73
59
  exclude(:CONSTRAINT_NAME=>'PRIMARY').
74
60
  exclude(:REFERENCED_TABLE_NAME=>nil).
75
- select(:CONSTRAINT_NAME___name, :COLUMN_NAME___column, :REFERENCED_TABLE_NAME___table, :REFERENCED_COLUMN_NAME___key)
61
+ order(:CONSTRAINT_NAME, :POSITION_IN_UNIQUE_CONSTRAINT).
62
+ select(Sequel[:CONSTRAINT_NAME].as(:name), Sequel[:COLUMN_NAME].as(:column), Sequel[:REFERENCED_TABLE_NAME].as(:table), Sequel[:REFERENCED_COLUMN_NAME].as(:key))
76
63
 
77
64
  h = {}
78
65
  ds.each do |row|
@@ -86,6 +73,13 @@ module Sequel
86
73
  h.values
87
74
  end
88
75
 
76
+ def freeze
77
+ server_version
78
+ mariadb?
79
+ supports_timestamp_usecs?
80
+ super
81
+ end
82
+
89
83
  # MySQL namespaces indexes per table.
90
84
  def global_index_namespace?
91
85
  false
@@ -100,10 +94,18 @@ module Sequel
100
94
  indexes = {}
101
95
  remove_indexes = []
102
96
  m = output_identifier_meth
103
- im = input_identifier_meth
104
- metadata_dataset.with_sql("SHOW INDEX FROM ?", SQL::Identifier.new(im.call(table))).each do |r|
97
+ schema, table = schema_and_table(table)
98
+
99
+ table = Sequel::SQL::Identifier.new(table)
100
+ sql = "SHOW INDEX FROM #{literal(table)}"
101
+ if schema
102
+ schema = Sequel::SQL::Identifier.new(schema)
103
+ sql += " FROM #{literal(schema)}"
104
+ end
105
+
106
+ metadata_dataset.with_sql(sql).each do |r|
105
107
  name = r[:Key_name]
106
- next if name == PRIMARY
108
+ next if name == 'PRIMARY'
107
109
  name = m.call(name)
108
110
  remove_indexes << name if r[:Sub_part] && ! opts[:partial]
109
111
  i = indexes[name] ||= {:columns=>[], :unique=>r[:Non_unique] != 1}
@@ -112,16 +114,20 @@ module Sequel
112
114
  indexes.reject{|k,v| remove_indexes.include?(k)}
113
115
  end
114
116
 
115
- # Rollback an existing prepared transaction with the given transaction
116
- # identifier string.
117
117
  def rollback_prepared_transaction(transaction_id, opts=OPTS)
118
118
  run("XA ROLLBACK #{literal(transaction_id)}", opts)
119
119
  end
120
120
 
121
+ # Whether the database is MariaDB and not MySQL
122
+ def mariadb?
123
+ return @is_mariadb if defined?(@is_mariadb)
124
+ @is_mariadb = !(fetch('SELECT version()').single_value! !~ /mariadb/i)
125
+ end
126
+
121
127
  # Get version of MySQL server, used for determined capabilities.
122
128
  def server_version
123
129
  @server_version ||= begin
124
- m = /(\d+)\.(\d+)\.(\d+)/.match(get(SQL::Function.new(:version)))
130
+ m = /(\d+)\.(\d+)\.(\d+)/.match(fetch('SELECT version()').single_value!)
125
131
  (m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
126
132
  end
127
133
  end
@@ -131,6 +137,11 @@ module Sequel
131
137
  true
132
138
  end
133
139
 
140
+ # Generated columns are supported in MariaDB 5.2.0+ and MySQL 5.7.6+.
141
+ def supports_generated_columns?
142
+ server_version >= (mariadb? ? 50200 : 50706)
143
+ end
144
+
134
145
  # MySQL 5+ supports prepared transactions (two-phase commit) using XA
135
146
  def supports_prepared_transactions?
136
147
  server_version >= 50000
@@ -152,7 +163,8 @@ module Sequel
152
163
  # automatic initialization of datetime values wasn't supported to 5.6.5+,
153
164
  # and this is related to that.
154
165
  def supports_timestamp_usecs?
155
- @supports_timestamp_usecs ||= server_version >= 50605 && typecast_value_boolean(opts[:fractional_seconds])
166
+ return @supports_timestamp_usecs if defined?(@supports_timestamp_usecs)
167
+ @supports_timestamp_usecs = server_version >= 50605 && typecast_value_boolean(opts[:fractional_seconds])
156
168
  end
157
169
 
158
170
  # MySQL supports transaction isolation levels
@@ -168,15 +180,6 @@ module Sequel
168
180
  full_tables('BASE TABLE', opts)
169
181
  end
170
182
 
171
- # Changes the database in use by issuing a USE statement. I would be
172
- # very careful if I used this.
173
- def use(db_name)
174
- disconnect
175
- @opts[:database] = db_name if self << "USE #{db_name}"
176
- @schemas = {}
177
- self
178
- end
179
-
180
183
  # Return an array of symbols specifying view names in the current database.
181
184
  #
182
185
  # Options:
@@ -184,21 +187,35 @@ module Sequel
184
187
  def views(opts=OPTS)
185
188
  full_tables('VIEW', opts)
186
189
  end
190
+
191
+ # Renames multiple tables in a single call.
192
+ #
193
+ # DB.rename_tables [:items, :old_items], [:other_items, :old_other_items]
194
+ # # RENAME TABLE items TO old_items, other_items TO old_other_items
195
+ def rename_tables(*renames)
196
+ execute_ddl(rename_tables_sql(renames))
197
+ renames.each{|from,| remove_cached_schema(from)}
198
+ end
187
199
 
188
200
  private
189
201
 
190
202
  def alter_table_add_column_sql(table, op)
191
- if related = op.delete(:table)
192
- sql = super.dup
203
+ pos = if after_col = op[:after]
204
+ " AFTER #{quote_identifier(after_col)}"
205
+ elsif op[:first]
206
+ " FIRST"
207
+ end
208
+
209
+ sql = if related = op.delete(:table)
210
+ sql = super + "#{pos}, ADD "
193
211
  op[:table] = related
194
212
  op[:key] ||= primary_key_from_schema(related)
195
- sql << ", ADD "
196
213
  if constraint_name = op.delete(:foreign_key_constraint_name)
197
214
  sql << "CONSTRAINT #{quote_identifier(constraint_name)} "
198
215
  end
199
216
  sql << "FOREIGN KEY (#{quote_identifier(op[:name])})#{column_references_sql(op)}"
200
217
  else
201
- super
218
+ "#{super}#{pos}"
202
219
  end
203
220
  end
204
221
 
@@ -224,7 +241,18 @@ module Sequel
224
241
  alias alter_table_rename_column_sql alter_table_change_column_sql
225
242
  alias alter_table_set_column_type_sql alter_table_change_column_sql
226
243
  alias alter_table_set_column_null_sql alter_table_change_column_sql
227
- alias alter_table_set_column_default_sql alter_table_change_column_sql
244
+
245
+ def alter_table_set_column_default_sql(table, op)
246
+ return super unless op[:default].nil?
247
+
248
+ opts = schema(table).find{|x| x[0] == op[:name]}
249
+
250
+ if opts && opts[1][:allow_null] == false
251
+ "ALTER COLUMN #{quote_identifier(op[:name])} DROP DEFAULT"
252
+ else
253
+ super
254
+ end
255
+ end
228
256
 
229
257
  def alter_table_add_constraint_sql(table, op)
230
258
  if op[:type] == :foreign_key
@@ -242,10 +270,13 @@ module Sequel
242
270
  "DROP FOREIGN KEY #{quote_identifier(name)}"
243
271
  when :unique
244
272
  "DROP INDEX #{quote_identifier(op[:name])}"
273
+ when :check, nil
274
+ if supports_check_constraints?
275
+ "DROP CONSTRAINT #{quote_identifier(op[:name])}"
276
+ end
245
277
  end
246
278
  end
247
279
 
248
- # MySQL server requires table names when dropping indexes.
249
280
  def alter_table_sql(table, op)
250
281
  case op[:op]
251
282
  when :drop_index
@@ -265,12 +296,17 @@ module Sequel
265
296
  # Handle MySQL specific default format.
266
297
  def column_schema_normalize_default(default, type)
267
298
  if column_schema_default_string_type?(type)
268
- return if [:date, :datetime, :time].include?(type) && MYSQL_TIMESTAMP_RE.match(default)
299
+ return if [:date, :datetime, :time].include?(type) && /\ACURRENT_(?:DATE|TIMESTAMP)?\z/.match(default)
269
300
  default = "'#{default.gsub("'", "''").gsub('\\', '\\\\')}'"
270
301
  end
271
302
  super(default, type)
272
303
  end
273
304
 
305
+ def column_schema_to_ruby_default(default, type)
306
+ return Sequel::CURRENT_DATE if mariadb? && server_version >= 100200 && default == 'curdate()'
307
+ super
308
+ end
309
+
274
310
  # Don't allow combining adding foreign key operations with other
275
311
  # operations, since in some cases adding a foreign key constraint in
276
312
  # the same query as other operations results in MySQL error 150.
@@ -297,12 +333,17 @@ module Sequel
297
333
  sqls << "SET sql_mode = '#{sql_mode}'"
298
334
  end
299
335
 
336
+ # Disable the use of split_materialized in the optimizer. This is
337
+ # needed to pass association tests on MariaDB 10.5+.
338
+ if opts[:disable_split_materialized] && typecast_value_boolean(opts[:disable_split_materialized])
339
+ sqls << "SET SESSION optimizer_switch='split_materialized=off'"
340
+ end
341
+
300
342
  sqls
301
343
  end
302
344
 
303
- # Use MySQL specific AUTO_INCREMENT text.
304
345
  def auto_increment_sql
305
- AUTO_INCREMENT
346
+ 'AUTO_INCREMENT'
306
347
  end
307
348
 
308
349
  # MySQL needs to set transaction isolation before begining a transaction
@@ -321,7 +362,29 @@ module Sequel
321
362
  end
322
363
  end
323
364
 
324
- # The order of the column definition, as an array of symbols.
365
+ # Support :on_update_current_timestamp option.
366
+ def column_definition_default_sql(sql, column)
367
+ super
368
+ sql << " ON UPDATE CURRENT_TIMESTAMP" if column[:on_update_current_timestamp]
369
+ end
370
+
371
+ # Add generation clause SQL fragment to column creation SQL.
372
+ def column_definition_generated_sql(sql, column)
373
+ if (generated_expression = column[:generated_always_as])
374
+ sql << " GENERATED ALWAYS AS (#{literal(generated_expression)})"
375
+ case (type = column[:generated_type])
376
+ when nil
377
+ # none, database default
378
+ when :virtual
379
+ sql << " VIRTUAL"
380
+ when :stored
381
+ sql << (mariadb? ? " PERSISTENT" : " STORED")
382
+ else
383
+ raise Error, "unsupported :generated_type option: #{type.inspect}"
384
+ end
385
+ end
386
+ end
387
+
325
388
  def column_definition_order
326
389
  COLUMN_DEFINITION_ORDER
327
390
  end
@@ -346,9 +409,9 @@ module Sequel
346
409
 
347
410
  # Use MySQL specific syntax for engine type and character encoding
348
411
  def create_table_sql(name, generator, options = OPTS)
349
- engine = options.fetch(:engine, Sequel::MySQL.default_engine)
350
- charset = options.fetch(:charset, Sequel::MySQL.default_charset)
351
- collate = options.fetch(:collate, Sequel::MySQL.default_collate)
412
+ engine = options.fetch(:engine, default_engine)
413
+ charset = options.fetch(:charset, default_charset)
414
+ collate = options.fetch(:collate, default_collate)
352
415
  generator.constraints.sort_by{|c| (c[:type] == :primary_key) ? -1 : 1}
353
416
 
354
417
  # Proc for figuring out the primary key for a given table.
@@ -398,6 +461,8 @@ module Sequel
398
461
  /foreign key constraint fails/ => ForeignKeyConstraintViolation,
399
462
  /cannot be null/ => NotNullConstraintViolation,
400
463
  /Deadlock found when trying to get lock; try restarting transaction/ => SerializationFailure,
464
+ /CONSTRAINT .+ failed for/ => CheckConstraintViolation,
465
+ /\A(Statement aborted because lock\(s\) could not be acquired immediately and NOWAIT is set\.|Lock wait timeout exceeded; try restarting transaction)/ => DatabaseLockTimeout,
401
466
  }.freeze
402
467
  def database_error_regexps
403
468
  DATABASE_ERROR_REGEXPS
@@ -409,17 +474,6 @@ module Sequel
409
474
  metadata_dataset.with_sql('SHOW FULL TABLES').server(opts[:server]).map{|r| m.call(r.values.first) if r.delete(:Table_type) == type}.compact
410
475
  end
411
476
 
412
- # MySQL folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on input.
413
- def identifier_input_method_default
414
- nil
415
- end
416
-
417
- # MySQL folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on output.
418
- def identifier_output_method_default
419
- nil
420
- end
421
-
422
- # Handle MySQL specific index SQL syntax
423
477
  def index_definition_sql(table_name, index)
424
478
  index_name = quote_identifier(index[:name] || default_index_name(table_name, index[:columns]))
425
479
  raise Error, "Partial indexes are not supported for this database" if index[:where] && !supports_partial_indexes?
@@ -440,6 +494,14 @@ module Sequel
440
494
  schema(table).select{|a| a[1][:primary_key]}.map{|a| a[0]}
441
495
  end
442
496
 
497
+ # SQL statement for renaming multiple tables.
498
+ def rename_tables_sql(renames)
499
+ rename_tos = renames.map do |from, to|
500
+ "#{quote_schema_table(from)} TO #{quote_schema_table(to)}"
501
+ end.join(', ')
502
+ "RENAME TABLE #{rename_tos}"
503
+ end
504
+
443
505
  # Rollback the currently open XA transaction
444
506
  def rollback_transaction(conn, opts=OPTS)
445
507
  if (s = opts[:prepare]) && savepoint_level(conn) <= 1
@@ -451,7 +513,6 @@ module Sequel
451
513
  end
452
514
  end
453
515
 
454
- # Recognize MySQL set type.
455
516
  def schema_column_type(db_type)
456
517
  case db_type
457
518
  when /\Aset/io
@@ -474,12 +535,17 @@ module Sequel
474
535
  metadata_dataset.with_sql("DESCRIBE ?", table).map do |row|
475
536
  extra = row.delete(:Extra)
476
537
  if row[:primary_key] = row.delete(:Key) == 'PRI'
477
- row[:auto_increment] = !!(extra.to_s =~ /auto_increment/io)
538
+ row[:auto_increment] = !!(extra.to_s =~ /auto_increment/i)
539
+ end
540
+ if supports_generated_columns?
541
+ # Extra field contains VIRTUAL or PERSISTENT for generated columns
542
+ row[:generated] = !!(extra.to_s =~ /VIRTUAL|STORED|PERSISTENT/i)
478
543
  end
479
544
  row[:allow_null] = row.delete(:Null) == 'YES'
480
545
  row[:default] = row.delete(:Default)
481
546
  row[:db_type] = row.delete(:Type)
482
547
  row[:type] = schema_column_type(row[:db_type])
548
+ row[:extra] = extra
483
549
  [m.call(row.delete(:Field)), row]
484
550
  end
485
551
  end
@@ -490,6 +556,12 @@ module Sequel
490
556
  server_version >= 50600 && (op[:op] == :drop_index || (op[:op] == :drop_constraint && op[:type] == :unique))
491
557
  end
492
558
 
559
+ # CHECK constraints only supported on MariaDB 10.2+ and MySQL 8.0.19+
560
+ # (at least MySQL documents DROP CONSTRAINT was supported in 8.0.19+).
561
+ def supports_check_constraints?
562
+ server_version >= (mariadb? ? 100200 : 80019)
563
+ end
564
+
493
565
  # MySQL can combine multiple alter table ops into a single query.
494
566
  def supports_combining_alter_table_ops?
495
567
  true
@@ -535,15 +607,11 @@ module Sequel
535
607
 
536
608
  # MySQL has both datetime and timestamp classes, most people are going
537
609
  # to want datetime.
538
- def type_literal_generic_time(column)
539
- if column[:only_time]
540
- if supports_timestamp_usecs?
541
- :'time(6)'
542
- else
543
- :time
544
- end
610
+ def type_literal_generic_only_time(column)
611
+ if supports_timestamp_usecs?
612
+ :'time(6)'
545
613
  else
546
- type_literal_generic_datetime(column)
614
+ :time
547
615
  end
548
616
  end
549
617
 
@@ -560,99 +628,57 @@ module Sequel
560
628
 
561
629
  # Dataset methods shared by datasets that use MySQL databases.
562
630
  module DatasetMethods
563
- BOOL_TRUE = '1'.freeze
564
- BOOL_FALSE = '0'.freeze
565
- COMMA_SEPARATOR = ', '.freeze
566
- FOR_SHARE = ' LOCK IN SHARE MODE'.freeze
567
- SQL_CALC_FOUND_ROWS = ' SQL_CALC_FOUND_ROWS'.freeze
568
- APOS = Dataset::APOS
569
- APOS_RE = Dataset::APOS_RE
570
- DOUBLE_APOS = Dataset::DOUBLE_APOS
571
- SPACE = Dataset::SPACE
572
- PAREN_OPEN = Dataset::PAREN_OPEN
573
- PAREN_CLOSE = Dataset::PAREN_CLOSE
574
- NOT_SPACE = Dataset::NOT_SPACE
575
- FROM = Dataset::FROM
576
- COMMA = Dataset::COMMA
577
- LIMIT = Dataset::LIMIT
578
- GROUP_BY = Dataset::GROUP_BY
579
- ESCAPE = Dataset::ESCAPE
580
- BACKSLASH = Dataset::BACKSLASH
581
- REGEXP = 'REGEXP'.freeze
582
- LIKE = 'LIKE'.freeze
583
- BINARY = 'BINARY '.freeze
584
- CONCAT = "CONCAT".freeze
585
- CAST_BITCOMP_OPEN = "CAST(~".freeze
586
- CAST_BITCOMP_CLOSE = " AS SIGNED INTEGER)".freeze
587
- STRAIGHT_JOIN = 'STRAIGHT_JOIN'.freeze
588
- NATURAL_LEFT_JOIN = 'NATURAL LEFT JOIN'.freeze
589
- BACKTICK = '`'.freeze
590
- BACKTICK_RE = /`/.freeze
591
- DOUBLE_BACKTICK = '``'.freeze
592
- EMPTY_COLUMNS = " ()".freeze
593
- EMPTY_VALUES = " VALUES ()".freeze
594
- IGNORE = " IGNORE".freeze
595
- ON_DUPLICATE_KEY_UPDATE = " ON DUPLICATE KEY UPDATE ".freeze
596
- EQ_VALUES = '=VALUES('.freeze
597
- EQ = '='.freeze
598
- WITH_ROLLUP = ' WITH ROLLUP'.freeze
599
- MATCH_AGAINST = ["(MATCH ".freeze, " AGAINST (".freeze, "))".freeze].freeze
600
- MATCH_AGAINST_BOOLEAN = ["(MATCH ".freeze, " AGAINST (".freeze, " IN BOOLEAN MODE))".freeze].freeze
601
- EXPLAIN = 'EXPLAIN '.freeze
602
- EXPLAIN_EXTENDED = 'EXPLAIN EXTENDED '.freeze
603
- BACKSLASH_RE = /\\/.freeze
604
- QUAD_BACKSLASH = "\\\\\\\\".freeze
605
- BLOB_START = "0x".freeze
606
- EMPTY_BLOB = "''".freeze
607
- HSTAR = "H*".freeze
608
- CURRENT_TIMESTAMP_56 = 'CURRENT_TIMESTAMP(6)'.freeze
609
-
610
- # Comes directly from MySQL's documentation, used for queries with limits without offsets
611
- ONLY_OFFSET = ",18446744073709551615".freeze
612
-
613
- Dataset.def_sql_method(self, :delete, %w'delete from where order limit')
631
+ MATCH_AGAINST = ["MATCH ".freeze, " AGAINST (".freeze, ")".freeze].freeze
632
+ MATCH_AGAINST_BOOLEAN = ["MATCH ".freeze, " AGAINST (".freeze, " IN BOOLEAN MODE)".freeze].freeze
633
+
634
+ Dataset.def_sql_method(self, :delete, %w'with delete from where order limit')
614
635
  Dataset.def_sql_method(self, :insert, %w'insert ignore into columns values on_duplicate_key_update')
615
- Dataset.def_sql_method(self, :select, %w'select distinct calc_found_rows columns from join where group having compounds order limit lock')
616
- Dataset.def_sql_method(self, :update, %w'update ignore table set where order limit')
636
+ Dataset.def_sql_method(self, :select, %w'with select distinct calc_found_rows columns from join where group having window compounds order limit lock')
637
+ Dataset.def_sql_method(self, :update, %w'with update ignore table set where order limit')
617
638
 
618
639
  include Sequel::Dataset::Replace
640
+ include UnmodifiedIdentifiers::DatasetMethods
619
641
 
620
- # MySQL specific syntax for LIKE/REGEXP searches, as well as
621
- # string concatenation.
622
642
  def complex_expression_sql_append(sql, op, args)
623
643
  case op
624
644
  when :IN, :"NOT IN"
625
- ds = args.at(1)
645
+ ds = args[1]
626
646
  if ds.is_a?(Sequel::Dataset) && ds.opts[:limit]
627
- super(sql, op, [args.at(0), ds.from_self])
647
+ super(sql, op, [args[0], ds.from_self])
628
648
  else
629
649
  super
630
650
  end
631
651
  when :~, :'!~', :'~*', :'!~*', :LIKE, :'NOT LIKE', :ILIKE, :'NOT ILIKE'
632
- sql << PAREN_OPEN
633
- literal_append(sql, args.at(0))
634
- sql << SPACE
652
+ if !db.mariadb? && db.server_version >= 80000 && [:~, :'!~'].include?(op)
653
+ func = Sequel.function(:REGEXP_LIKE, args[0], args[1], 'c')
654
+ func = ~func if op == :'!~'
655
+ return literal_append(sql, func)
656
+ end
657
+
658
+ sql << '('
659
+ literal_append(sql, args[0])
660
+ sql << ' '
635
661
  sql << 'NOT ' if [:'NOT LIKE', :'NOT ILIKE', :'!~', :'!~*'].include?(op)
636
- sql << ([:~, :'!~', :'~*', :'!~*'].include?(op) ? REGEXP : LIKE)
637
- sql << SPACE
638
- sql << BINARY if [:~, :'!~', :LIKE, :'NOT LIKE'].include?(op)
639
- literal_append(sql, args.at(1))
662
+ sql << ([:~, :'!~', :'~*', :'!~*'].include?(op) ? 'REGEXP' : 'LIKE')
663
+ sql << ' '
664
+ sql << 'BINARY ' if [:~, :'!~', :LIKE, :'NOT LIKE'].include?(op)
665
+ literal_append(sql, args[1])
640
666
  if [:LIKE, :'NOT LIKE', :ILIKE, :'NOT ILIKE'].include?(op)
641
- sql << ESCAPE
642
- literal_append(sql, BACKSLASH)
667
+ sql << " ESCAPE "
668
+ literal_append(sql, "\\")
643
669
  end
644
- sql << PAREN_CLOSE
670
+ sql << ')'
645
671
  when :'||'
646
672
  if args.length > 1
647
- sql << CONCAT
673
+ sql << "CONCAT"
648
674
  array_sql_append(sql, args)
649
675
  else
650
- literal_append(sql, args.at(0))
676
+ literal_append(sql, args[0])
651
677
  end
652
678
  when :'B~'
653
- sql << CAST_BITCOMP_OPEN
654
- literal_append(sql, args.at(0))
655
- sql << CAST_BITCOMP_CLOSE
679
+ sql << "CAST(~"
680
+ literal_append(sql, args[0])
681
+ sql << " AS SIGNED INTEGER)"
656
682
  else
657
683
  super
658
684
  end
@@ -664,7 +690,7 @@ module Sequel
664
690
  # fractional seconds.
665
691
  def constant_sql_append(sql, constant)
666
692
  if constant == :CURRENT_TIMESTAMP && supports_timestamp_usecs?
667
- sql << CURRENT_TIMESTAMP_56
693
+ sql << 'CURRENT_TIMESTAMP(6)'
668
694
  else
669
695
  super
670
696
  end
@@ -686,22 +712,22 @@ module Sequel
686
712
  # Sets up the select methods to delete from if deleting from a
687
713
  # joined dataset:
688
714
  #
689
- # DB[:a].join(:b, :a_id=>:id).delete
715
+ # DB[:a].join(:b, a_id: :id).delete
690
716
  # # DELETE a FROM a INNER JOIN b ON (b.a_id = a.id)
691
717
  #
692
- # DB[:a].join(:b, :a_id=>:id).delete_from(:a, :b).delete
718
+ # DB[:a].join(:b, a_id: :id).delete_from(:a, :b).delete
693
719
  # # DELETE a, b FROM a INNER JOIN b ON (b.a_id = a.id)
694
720
  def delete_from(*tables)
695
721
  clone(:delete_from=>tables)
696
722
  end
697
723
 
698
724
  # Return the results of an EXPLAIN query as a string. Options:
699
- # :extended :: Use EXPLAIN EXPTENDED instead of EXPLAIN if true.
725
+ # :extended :: Use EXPLAIN EXTENDED instead of EXPLAIN if true.
700
726
  def explain(opts=OPTS)
701
727
  # Load the PrettyTable class, needed for explain output
702
728
  Sequel.extension(:_pretty_table) unless defined?(Sequel::PrettyTable)
703
729
 
704
- ds = db.send(:metadata_dataset).with_sql((opts[:extended] ? EXPLAIN_EXTENDED : EXPLAIN) + select_sql).naked
730
+ ds = db.send(:metadata_dataset).with_sql(((opts[:extended] && (db.mariadb? || db.server_version < 50700)) ? 'EXPLAIN EXTENDED ' : 'EXPLAIN ') + select_sql).naked
705
731
  rows = ds.all
706
732
  Sequel::PrettyTable.string(rows, ds.columns)
707
733
  end
@@ -713,7 +739,7 @@ module Sequel
713
739
 
714
740
  # Adds full text filter
715
741
  def full_text_search(cols, terms, opts = OPTS)
716
- filter(full_text_sql(cols, terms, opts))
742
+ where(full_text_sql(cols, terms, opts))
717
743
  end
718
744
 
719
745
  # MySQL specific full text search syntax.
@@ -722,33 +748,12 @@ module Sequel
722
748
  SQL::PlaceholderLiteralString.new((opts[:boolean] ? MATCH_AGAINST_BOOLEAN : MATCH_AGAINST), [Array(cols), terms])
723
749
  end
724
750
 
725
- # Transforms an CROSS JOIN to an INNER JOIN if the expr is not nil.
726
- # Raises an error on use of :full_outer type, since MySQL doesn't support it.
727
- def join_table(type, table, expr=nil, opts=OPTS, &block)
728
- type = :inner if (type == :cross) && !expr.nil?
729
- raise(Sequel::Error, "MySQL doesn't support FULL OUTER JOIN") if type == :full_outer
730
- super(type, table, expr, opts, &block)
731
- end
732
-
733
- # Transforms :natural_inner to NATURAL LEFT JOIN and straight to
734
- # STRAIGHT_JOIN.
735
- def join_type_sql(join_type)
736
- case join_type
737
- when :straight
738
- STRAIGHT_JOIN
739
- when :natural_inner
740
- NATURAL_LEFT_JOIN
741
- else
742
- super
743
- end
744
- end
745
-
746
751
  # Sets up the insert methods to use INSERT IGNORE.
747
752
  # Useful if you have a unique key and want to just skip
748
753
  # inserting rows that violate the unique key restriction.
749
754
  #
750
755
  # dataset.insert_ignore.multi_insert(
751
- # [{:name => 'a', :value => 1}, {:name => 'b', :value => 2}]
756
+ # [{name: 'a', value: 1}, {name: 'b', value: 2}]
752
757
  # )
753
758
  # # INSERT IGNORE INTO tablename (name, value) VALUES (a, 1), (b, 2)
754
759
  def insert_ignore
@@ -766,21 +771,21 @@ module Sequel
766
771
  # inserting rows that violate the unique key restriction.
767
772
  #
768
773
  # dataset.on_duplicate_key_update.multi_insert(
769
- # [{:name => 'a', :value => 1}, {:name => 'b', :value => 2}]
774
+ # [{name: 'a', value: 1}, {name: 'b', value: 2}]
770
775
  # )
771
776
  # # INSERT INTO tablename (name, value) VALUES (a, 1), (b, 2)
772
777
  # # ON DUPLICATE KEY UPDATE name=VALUES(name), value=VALUES(value)
773
778
  #
774
779
  # dataset.on_duplicate_key_update(:value).multi_insert(
775
- # [{:name => 'a', :value => 1}, {:name => 'b', :value => 2}]
780
+ # [{name: 'a', value: 1}, {name: 'b', value: 2}]
776
781
  # )
777
782
  # # INSERT INTO tablename (name, value) VALUES (a, 1), (b, 2)
778
783
  # # ON DUPLICATE KEY UPDATE value=VALUES(value)
779
784
  #
780
785
  # dataset.on_duplicate_key_update(
781
- # :value => Sequel.lit('value + VALUES(value)')
786
+ # value: Sequel.lit('value + VALUES(value)')
782
787
  # ).multi_insert(
783
- # [{:name => 'a', :value => 1}, {:name => 'b', :value => 2}]
788
+ # [{name: 'a', value: 1}, {name: 'b', value: 2}]
784
789
  # )
785
790
  # # INSERT INTO tablename (name, value) VALUES (a, 1), (b, 2)
786
791
  # # ON DUPLICATE KEY UPDATE value=value + VALUES(value)
@@ -790,7 +795,19 @@ module Sequel
790
795
 
791
796
  # MySQL uses the nonstandard ` (backtick) for quoting identifiers.
792
797
  def quoted_identifier_append(sql, c)
793
- sql << BACKTICK << c.to_s.gsub(BACKTICK_RE, DOUBLE_BACKTICK) << BACKTICK
798
+ sql << '`' << c.to_s.gsub('`', '``') << '`'
799
+ end
800
+
801
+ # MariaDB 10.2+ and MySQL 8+ support CTEs
802
+ def supports_cte?(type=:select)
803
+ if db.mariadb?
804
+ type == :select && db.server_version >= 100200
805
+ else
806
+ case type
807
+ when :select, :update, :delete
808
+ db.server_version >= 80000
809
+ end
810
+ end
794
811
  end
795
812
 
796
813
  # MySQL does not support derived column lists
@@ -809,9 +826,9 @@ module Sequel
809
826
  true
810
827
  end
811
828
 
812
- # MySQL does not support INTERSECT or EXCEPT
829
+ # MariaDB 10.3+ supports INTERSECT or EXCEPT
813
830
  def supports_intersect_except?
814
- false
831
+ db.mariadb? && db.server_version >= 100300
815
832
  end
816
833
 
817
834
  # MySQL does not support limits in correlated subqueries (or any subqueries that use IN).
@@ -824,8 +841,13 @@ module Sequel
824
841
  true
825
842
  end
826
843
 
844
+ # MySQL 8+ and MariaDB 10.3+ support NOWAIT.
845
+ def supports_nowait?
846
+ db.server_version >= (db.mariadb? ? 100300 : 80000)
847
+ end
848
+
827
849
  # MySQL's DISTINCT ON emulation using GROUP BY does not respect the
828
- # queries ORDER BY clause.
850
+ # query's ORDER BY clause.
829
851
  def supports_ordered_distinct_on?
830
852
  false
831
853
  end
@@ -835,18 +857,32 @@ module Sequel
835
857
  true
836
858
  end
837
859
 
838
- # MySQL does support fractional timestamps in literal timestamps, but it
839
- # ignores them. Also, using them seems to cause problems on 1.9. Since
840
- # they are ignored anyway, not using them is probably best.
860
+ # MySQL 8+ supports SKIP LOCKED.
861
+ def supports_skip_locked?
862
+ !db.mariadb? && db.server_version >= 80000
863
+ end
864
+
865
+ # Check the database setting for whether fractional timestamps
866
+ # are suppported.
841
867
  def supports_timestamp_usecs?
842
868
  db.supports_timestamp_usecs?
843
869
  end
844
-
870
+
871
+ # MySQL 8+ supports WINDOW clause.
872
+ def supports_window_clause?
873
+ !db.mariadb? && db.server_version >= 80000
874
+ end
875
+
876
+ # MariaDB 10.2+ and MySQL 8+ support window functions
877
+ def supports_window_functions?
878
+ db.server_version >= (db.mariadb? ? 100200 : 80000)
879
+ end
880
+
845
881
  # Sets up the update methods to use UPDATE IGNORE.
846
882
  # Useful if you have a unique key and want to just skip
847
883
  # updating rows that violate the unique key restriction.
848
884
  #
849
- # dataset.update_ignore.update({:name => 'a', :value => 1})
885
+ # dataset.update_ignore.update(name: 'a', value: 1)
850
886
  # # UPDATE IGNORE tablename SET name = 'a', value = 1
851
887
  def update_ignore
852
888
  clone(:update_ignore=>true)
@@ -854,14 +890,19 @@ module Sequel
854
890
 
855
891
  private
856
892
 
893
+ # Allow update and delete for limited datasets, unless there is an offset.
894
+ def check_not_limited!(type)
895
+ super if type == :truncate || @opts[:offset]
896
+ end
897
+
857
898
  # Consider the first table in the joined dataset is the table to delete
858
899
  # from, but include the others for the purposes of selecting rows.
859
900
  def delete_from_sql(sql)
860
901
  if joined_dataset?
861
- sql << SPACE
902
+ sql << ' '
862
903
  tables = @opts[:delete_from] || @opts[:from][0..0]
863
904
  source_list_append(sql, tables)
864
- sql << FROM
905
+ sql << ' FROM '
865
906
  source_list_append(sql, @opts[:from])
866
907
  select_join_sql(sql)
867
908
  else
@@ -873,7 +914,7 @@ module Sequel
873
914
  def insert_columns_sql(sql)
874
915
  values = opts[:values]
875
916
  if values.is_a?(Array) && values.empty?
876
- sql << EMPTY_COLUMNS
917
+ sql << " ()"
877
918
  else
878
919
  super
879
920
  end
@@ -881,12 +922,12 @@ module Sequel
881
922
 
882
923
  # MySQL supports INSERT IGNORE INTO
883
924
  def insert_ignore_sql(sql)
884
- sql << IGNORE if opts[:insert_ignore]
925
+ sql << " IGNORE" if opts[:insert_ignore]
885
926
  end
886
927
 
887
928
  # MySQL supports UPDATE IGNORE
888
929
  def update_ignore_sql(sql)
889
- sql << IGNORE if opts[:update_ignore]
930
+ sql << " IGNORE" if opts[:update_ignore]
890
931
  end
891
932
 
892
933
  # MySQL supports INSERT ... ON DUPLICATE KEY UPDATE
@@ -901,11 +942,11 @@ module Sequel
901
942
  update_cols = update_cols[0..-2]
902
943
  end
903
944
 
904
- sql << ON_DUPLICATE_KEY_UPDATE
945
+ sql << " ON DUPLICATE KEY UPDATE "
905
946
  c = false
906
- co = COMMA
907
- values = EQ_VALUES
908
- endp = PAREN_CLOSE
947
+ co = ', '
948
+ values = '=VALUES('
949
+ endp = ')'
909
950
  update_cols.each do |col|
910
951
  sql << co if c
911
952
  quote_identifier_append(sql, col)
@@ -915,7 +956,7 @@ module Sequel
915
956
  c ||= true
916
957
  end
917
958
  if update_vals
918
- eq = EQ
959
+ eq = '='
919
960
  update_vals.map do |col,v|
920
961
  sql << co if c
921
962
  quote_identifier_append(sql, col)
@@ -931,16 +972,25 @@ module Sequel
931
972
  def insert_values_sql(sql)
932
973
  values = opts[:values]
933
974
  if values.is_a?(Array) && values.empty?
934
- sql << EMPTY_VALUES
975
+ sql << " VALUES ()"
935
976
  else
936
977
  super
937
978
  end
938
979
  end
939
980
 
981
+ # Transforms :straight to STRAIGHT_JOIN.
982
+ def join_type_sql(join_type)
983
+ if join_type == :straight
984
+ 'STRAIGHT_JOIN'
985
+ else
986
+ super
987
+ end
988
+ end
989
+
940
990
  # MySQL allows a LIMIT in DELETE and UPDATE statements.
941
991
  def limit_sql(sql)
942
992
  if l = @opts[:limit]
943
- sql << LIMIT
993
+ sql << " LIMIT "
944
994
  literal_append(sql, l)
945
995
  end
946
996
  end
@@ -950,15 +1000,15 @@ module Sequel
950
1000
  # MySQL uses a preceding X for hex escaping strings
951
1001
  def literal_blob_append(sql, v)
952
1002
  if v.empty?
953
- sql << EMPTY_BLOB
1003
+ sql << "''"
954
1004
  else
955
- sql << BLOB_START << v.unpack(HSTAR).first
1005
+ sql << "0x" << v.unpack("H*").first
956
1006
  end
957
1007
  end
958
1008
 
959
1009
  # Use 0 for false on MySQL
960
1010
  def literal_false
961
- BOOL_FALSE
1011
+ '0'
962
1012
  end
963
1013
 
964
1014
  # Raise error for infinitate and NaN values
@@ -972,33 +1022,65 @@ module Sequel
972
1022
 
973
1023
  # SQL fragment for String. Doubles \ and ' by default.
974
1024
  def literal_string_append(sql, v)
975
- sql << APOS << v.gsub(BACKSLASH_RE, QUAD_BACKSLASH).gsub(APOS_RE, DOUBLE_APOS) << APOS
1025
+ sql << "'" << v.gsub("\\", "\\\\\\\\").gsub("'", "''") << "'"
976
1026
  end
977
1027
 
978
1028
  # Use 1 for true on MySQL
979
1029
  def literal_true
980
- BOOL_TRUE
1030
+ '1'
981
1031
  end
982
1032
 
983
- # MySQL supports multiple rows in INSERT.
1033
+ # MySQL supports multiple rows in VALUES in INSERT.
984
1034
  def multi_insert_sql_strategy
985
1035
  :values
986
1036
  end
987
1037
 
1038
+ def non_sql_option?(key)
1039
+ super || key == :insert_ignore || key == :update_ignore || key == :on_duplicate_key_update
1040
+ end
1041
+
1042
+ # MySQL does not natively support NULLS FIRST/LAST.
1043
+ def requires_emulating_nulls_first?
1044
+ true
1045
+ end
1046
+
988
1047
  def select_only_offset_sql(sql)
989
- sql << LIMIT
1048
+ sql << " LIMIT "
990
1049
  literal_append(sql, @opts[:offset])
991
- sql << ONLY_OFFSET
1050
+ sql << ",18446744073709551615"
992
1051
  end
993
1052
 
994
1053
  # Support FOR SHARE locking when using the :share lock style.
1054
+ # Use SKIP LOCKED if skipping locked rows.
995
1055
  def select_lock_sql(sql)
996
- @opts[:lock] == :share ? (sql << FOR_SHARE) : super
1056
+ lock = @opts[:lock]
1057
+ if lock == :share
1058
+ if !db.mariadb? && db.server_version >= 80000
1059
+ sql << ' FOR SHARE'
1060
+ else
1061
+ sql << ' LOCK IN SHARE MODE'
1062
+ end
1063
+ else
1064
+ super
1065
+ end
1066
+
1067
+ if lock
1068
+ if @opts[:skip_locked]
1069
+ sql << " SKIP LOCKED"
1070
+ elsif @opts[:nowait]
1071
+ sql << " NOWAIT"
1072
+ end
1073
+ end
997
1074
  end
998
1075
 
999
1076
  # MySQL specific SQL_CALC_FOUND_ROWS option
1000
1077
  def select_calc_found_rows_sql(sql)
1001
- sql << SQL_CALC_FOUND_ROWS if opts[:calc_found_rows]
1078
+ sql << ' SQL_CALC_FOUND_ROWS' if opts[:calc_found_rows]
1079
+ end
1080
+
1081
+ # Use WITH RECURSIVE instead of WITH if any of the CTEs is recursive
1082
+ def select_with_sql_base
1083
+ opts[:with].any?{|w| w[:recursive]} ? "WITH RECURSIVE " : super
1002
1084
  end
1003
1085
 
1004
1086
  # MySQL uses WITH ROLLUP syntax.