sequel 4.26.0 → 5.37.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 (692) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG +405 -5656
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +232 -157
  5. data/bin/sequel +32 -9
  6. data/doc/advanced_associations.rdoc +252 -188
  7. data/doc/association_basics.rdoc +231 -273
  8. data/doc/bin_sequel.rdoc +5 -3
  9. data/doc/cheat_sheet.rdoc +75 -48
  10. data/doc/code_order.rdoc +28 -10
  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/mass_assignment.rdoc +74 -31
  16. data/doc/migration.rdoc +72 -46
  17. data/doc/model_dataset_method_design.rdoc +129 -0
  18. data/doc/model_hooks.rdoc +15 -25
  19. data/doc/model_plugins.rdoc +12 -12
  20. data/doc/mssql_stored_procedures.rdoc +3 -3
  21. data/doc/object_model.rdoc +59 -69
  22. data/doc/opening_databases.rdoc +84 -94
  23. data/doc/postgresql.rdoc +268 -38
  24. data/doc/prepared_statements.rdoc +29 -24
  25. data/doc/querying.rdoc +184 -164
  26. data/doc/reflection.rdoc +5 -6
  27. data/doc/release_notes/5.0.0.txt +159 -0
  28. data/doc/release_notes/5.1.0.txt +31 -0
  29. data/doc/release_notes/5.10.0.txt +84 -0
  30. data/doc/release_notes/5.11.0.txt +83 -0
  31. data/doc/release_notes/5.12.0.txt +141 -0
  32. data/doc/release_notes/5.13.0.txt +27 -0
  33. data/doc/release_notes/5.14.0.txt +63 -0
  34. data/doc/release_notes/5.15.0.txt +39 -0
  35. data/doc/release_notes/5.16.0.txt +110 -0
  36. data/doc/release_notes/5.17.0.txt +31 -0
  37. data/doc/release_notes/5.18.0.txt +69 -0
  38. data/doc/release_notes/5.19.0.txt +28 -0
  39. data/doc/release_notes/5.2.0.txt +33 -0
  40. data/doc/release_notes/5.20.0.txt +89 -0
  41. data/doc/release_notes/5.21.0.txt +87 -0
  42. data/doc/release_notes/5.22.0.txt +48 -0
  43. data/doc/release_notes/5.23.0.txt +56 -0
  44. data/doc/release_notes/5.24.0.txt +56 -0
  45. data/doc/release_notes/5.25.0.txt +32 -0
  46. data/doc/release_notes/5.26.0.txt +35 -0
  47. data/doc/release_notes/5.27.0.txt +21 -0
  48. data/doc/release_notes/5.28.0.txt +16 -0
  49. data/doc/release_notes/5.29.0.txt +22 -0
  50. data/doc/release_notes/5.3.0.txt +121 -0
  51. data/doc/release_notes/5.30.0.txt +20 -0
  52. data/doc/release_notes/5.31.0.txt +148 -0
  53. data/doc/release_notes/5.32.0.txt +46 -0
  54. data/doc/release_notes/5.33.0.txt +24 -0
  55. data/doc/release_notes/5.34.0.txt +40 -0
  56. data/doc/release_notes/5.35.0.txt +56 -0
  57. data/doc/release_notes/5.36.0.txt +60 -0
  58. data/doc/release_notes/5.37.0.txt +30 -0
  59. data/doc/release_notes/5.4.0.txt +80 -0
  60. data/doc/release_notes/5.5.0.txt +61 -0
  61. data/doc/release_notes/5.6.0.txt +31 -0
  62. data/doc/release_notes/5.7.0.txt +108 -0
  63. data/doc/release_notes/5.8.0.txt +170 -0
  64. data/doc/release_notes/5.9.0.txt +99 -0
  65. data/doc/schema_modification.rdoc +102 -77
  66. data/doc/security.rdoc +160 -87
  67. data/doc/sharding.rdoc +74 -47
  68. data/doc/sql.rdoc +135 -122
  69. data/doc/testing.rdoc +34 -18
  70. data/doc/thread_safety.rdoc +2 -4
  71. data/doc/transactions.rdoc +101 -19
  72. data/doc/validations.rdoc +64 -51
  73. data/doc/virtual_rows.rdoc +90 -109
  74. data/lib/sequel.rb +3 -1
  75. data/lib/sequel/adapters/ado.rb +154 -22
  76. data/lib/sequel/adapters/ado/access.rb +21 -21
  77. data/lib/sequel/adapters/ado/mssql.rb +8 -15
  78. data/lib/sequel/adapters/amalgalite.rb +17 -25
  79. data/lib/sequel/adapters/ibmdb.rb +52 -58
  80. data/lib/sequel/adapters/jdbc.rb +149 -127
  81. data/lib/sequel/adapters/jdbc/db2.rb +32 -40
  82. data/lib/sequel/adapters/jdbc/derby.rb +56 -58
  83. data/lib/sequel/adapters/jdbc/h2.rb +40 -30
  84. data/lib/sequel/adapters/jdbc/hsqldb.rb +22 -33
  85. data/lib/sequel/adapters/jdbc/jtds.rb +4 -10
  86. data/lib/sequel/adapters/jdbc/mssql.rb +6 -12
  87. data/lib/sequel/adapters/jdbc/mysql.rb +17 -18
  88. data/lib/sequel/adapters/jdbc/oracle.rb +25 -19
  89. data/lib/sequel/adapters/jdbc/postgresql.rb +90 -69
  90. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +14 -24
  91. data/lib/sequel/adapters/jdbc/sqlite.rb +50 -12
  92. data/lib/sequel/adapters/jdbc/sqlserver.rb +36 -9
  93. data/lib/sequel/adapters/jdbc/transactions.rb +25 -39
  94. data/lib/sequel/adapters/mock.rb +104 -113
  95. data/lib/sequel/adapters/mysql.rb +42 -61
  96. data/lib/sequel/adapters/mysql2.rb +126 -35
  97. data/lib/sequel/adapters/odbc.rb +21 -28
  98. data/lib/sequel/adapters/odbc/db2.rb +3 -1
  99. data/lib/sequel/adapters/odbc/mssql.rb +11 -15
  100. data/lib/sequel/adapters/odbc/oracle.rb +11 -0
  101. data/lib/sequel/adapters/oracle.rb +62 -68
  102. data/lib/sequel/adapters/postgres.rb +257 -311
  103. data/lib/sequel/adapters/postgresql.rb +3 -1
  104. data/lib/sequel/adapters/shared/access.rb +75 -79
  105. data/lib/sequel/adapters/shared/db2.rb +96 -74
  106. data/lib/sequel/adapters/shared/mssql.rb +258 -213
  107. data/lib/sequel/adapters/shared/mysql.rb +284 -216
  108. data/lib/sequel/adapters/shared/oracle.rb +175 -60
  109. data/lib/sequel/adapters/shared/postgres.rb +829 -383
  110. data/lib/sequel/adapters/shared/sqlanywhere.rb +105 -127
  111. data/lib/sequel/adapters/shared/sqlite.rb +382 -159
  112. data/lib/sequel/adapters/sqlanywhere.rb +53 -38
  113. data/lib/sequel/adapters/sqlite.rb +111 -105
  114. data/lib/sequel/adapters/tinytds.rb +38 -46
  115. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +8 -9
  116. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -5
  117. data/lib/sequel/adapters/utils/mysql_mysql2.rb +87 -0
  118. data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +56 -0
  119. data/lib/sequel/adapters/utils/replace.rb +3 -4
  120. data/lib/sequel/adapters/utils/split_alter_table.rb +2 -0
  121. data/lib/sequel/adapters/utils/stored_procedures.rb +9 -22
  122. data/lib/sequel/adapters/utils/unmodified_identifiers.rb +28 -0
  123. data/lib/sequel/ast_transformer.rb +13 -89
  124. data/lib/sequel/connection_pool.rb +54 -26
  125. data/lib/sequel/connection_pool/sharded_single.rb +19 -12
  126. data/lib/sequel/connection_pool/sharded_threaded.rb +160 -111
  127. data/lib/sequel/connection_pool/single.rb +21 -12
  128. data/lib/sequel/connection_pool/threaded.rb +137 -119
  129. data/lib/sequel/core.rb +352 -320
  130. data/lib/sequel/database.rb +19 -2
  131. data/lib/sequel/database/connecting.rb +70 -55
  132. data/lib/sequel/database/dataset.rb +15 -5
  133. data/lib/sequel/database/dataset_defaults.rb +20 -102
  134. data/lib/sequel/database/features.rb +20 -4
  135. data/lib/sequel/database/logging.rb +25 -7
  136. data/lib/sequel/database/misc.rb +132 -118
  137. data/lib/sequel/database/query.rb +51 -28
  138. data/lib/sequel/database/schema_generator.rb +188 -75
  139. data/lib/sequel/database/schema_methods.rb +161 -92
  140. data/lib/sequel/database/transactions.rb +260 -58
  141. data/lib/sequel/dataset.rb +28 -12
  142. data/lib/sequel/dataset/actions.rb +354 -170
  143. data/lib/sequel/dataset/dataset_module.rb +46 -0
  144. data/lib/sequel/dataset/features.rb +81 -34
  145. data/lib/sequel/dataset/graph.rb +82 -58
  146. data/lib/sequel/dataset/misc.rb +139 -47
  147. data/lib/sequel/dataset/placeholder_literalizer.rb +66 -26
  148. data/lib/sequel/dataset/prepared_statements.rb +188 -85
  149. data/lib/sequel/dataset/query.rb +428 -214
  150. data/lib/sequel/dataset/sql.rb +446 -339
  151. data/lib/sequel/deprecated.rb +14 -2
  152. data/lib/sequel/exceptions.rb +48 -16
  153. data/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
  154. data/lib/sequel/extensions/_model_pg_row.rb +43 -0
  155. data/lib/sequel/extensions/_pretty_table.rb +10 -9
  156. data/lib/sequel/extensions/any_not_empty.rb +45 -0
  157. data/lib/sequel/extensions/arbitrary_servers.rb +15 -11
  158. data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
  159. data/lib/sequel/extensions/blank.rb +2 -0
  160. data/lib/sequel/extensions/caller_logging.rb +79 -0
  161. data/lib/sequel/extensions/columns_introspection.rb +9 -4
  162. data/lib/sequel/extensions/connection_expiration.rb +99 -0
  163. data/lib/sequel/extensions/connection_validator.rb +26 -13
  164. data/lib/sequel/extensions/constant_sql_override.rb +65 -0
  165. data/lib/sequel/extensions/constraint_validations.rb +93 -38
  166. data/lib/sequel/extensions/core_extensions.rb +45 -53
  167. data/lib/sequel/extensions/core_refinements.rb +44 -46
  168. data/lib/sequel/extensions/current_datetime_timestamp.rb +5 -4
  169. data/lib/sequel/extensions/dataset_source_alias.rb +4 -0
  170. data/lib/sequel/extensions/date_arithmetic.rb +42 -16
  171. data/lib/sequel/extensions/datetime_parse_to_time.rb +37 -0
  172. data/lib/sequel/extensions/duplicate_columns_handler.rb +94 -0
  173. data/lib/sequel/extensions/empty_array_consider_nulls.rb +7 -3
  174. data/lib/sequel/extensions/error_sql.rb +7 -3
  175. data/lib/sequel/extensions/escaped_like.rb +100 -0
  176. data/lib/sequel/extensions/eval_inspect.rb +14 -15
  177. data/lib/sequel/extensions/exclude_or_null.rb +68 -0
  178. data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  179. data/lib/sequel/extensions/freeze_datasets.rb +3 -0
  180. data/lib/sequel/extensions/from_block.rb +2 -31
  181. data/lib/sequel/extensions/graph_each.rb +19 -6
  182. data/lib/sequel/extensions/identifier_mangling.rb +180 -0
  183. data/lib/sequel/extensions/implicit_subquery.rb +48 -0
  184. data/lib/sequel/extensions/index_caching.rb +109 -0
  185. data/lib/sequel/extensions/inflector.rb +8 -4
  186. data/lib/sequel/extensions/integer64.rb +32 -0
  187. data/lib/sequel/extensions/looser_typecasting.rb +19 -9
  188. data/lib/sequel/extensions/migration.rb +132 -80
  189. data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +4 -0
  190. data/lib/sequel/extensions/named_timezones.rb +88 -23
  191. data/lib/sequel/extensions/no_auto_literal_strings.rb +4 -0
  192. data/lib/sequel/extensions/null_dataset.rb +12 -8
  193. data/lib/sequel/extensions/pagination.rb +35 -28
  194. data/lib/sequel/extensions/pg_array.rb +227 -316
  195. data/lib/sequel/extensions/pg_array_ops.rb +19 -7
  196. data/lib/sequel/extensions/pg_enum.rb +69 -24
  197. data/lib/sequel/extensions/pg_extended_date_support.rb +250 -0
  198. data/lib/sequel/extensions/pg_hstore.rb +50 -59
  199. data/lib/sequel/extensions/pg_hstore_ops.rb +9 -3
  200. data/lib/sequel/extensions/pg_inet.rb +34 -15
  201. data/lib/sequel/extensions/pg_inet_ops.rb +5 -1
  202. data/lib/sequel/extensions/pg_interval.rb +26 -26
  203. data/lib/sequel/extensions/pg_json.rb +422 -141
  204. data/lib/sequel/extensions/pg_json_ops.rb +248 -9
  205. data/lib/sequel/extensions/pg_loose_count.rb +5 -1
  206. data/lib/sequel/extensions/pg_range.rb +162 -146
  207. data/lib/sequel/extensions/pg_range_ops.rb +10 -5
  208. data/lib/sequel/extensions/pg_row.rb +53 -87
  209. data/lib/sequel/extensions/pg_row_ops.rb +36 -13
  210. data/lib/sequel/extensions/pg_static_cache_updater.rb +6 -2
  211. data/lib/sequel/extensions/pg_timestamptz.rb +28 -0
  212. data/lib/sequel/extensions/pretty_table.rb +4 -0
  213. data/lib/sequel/extensions/query.rb +12 -7
  214. data/lib/sequel/extensions/round_timestamps.rb +6 -9
  215. data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  216. data/lib/sequel/extensions/s.rb +59 -0
  217. data/lib/sequel/extensions/schema_caching.rb +14 -1
  218. data/lib/sequel/extensions/schema_dumper.rb +83 -55
  219. data/lib/sequel/extensions/select_remove.rb +8 -4
  220. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +85 -0
  221. data/lib/sequel/extensions/server_block.rb +50 -17
  222. data/lib/sequel/extensions/server_logging.rb +61 -0
  223. data/lib/sequel/extensions/split_array_nil.rb +8 -4
  224. data/lib/sequel/extensions/sql_comments.rb +96 -0
  225. data/lib/sequel/extensions/sql_expr.rb +4 -1
  226. data/lib/sequel/extensions/string_agg.rb +181 -0
  227. data/lib/sequel/extensions/string_date_time.rb +2 -0
  228. data/lib/sequel/extensions/symbol_aref.rb +53 -0
  229. data/lib/sequel/extensions/symbol_aref_refinement.rb +43 -0
  230. data/lib/sequel/extensions/symbol_as.rb +23 -0
  231. data/lib/sequel/extensions/symbol_as_refinement.rb +37 -0
  232. data/lib/sequel/extensions/synchronize_sql.rb +45 -0
  233. data/lib/sequel/extensions/thread_local_timezones.rb +4 -0
  234. data/lib/sequel/extensions/to_dot.rb +15 -5
  235. data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
  236. data/lib/sequel/model.rb +36 -126
  237. data/lib/sequel/model/associations.rb +850 -257
  238. data/lib/sequel/model/base.rb +652 -764
  239. data/lib/sequel/model/dataset_module.rb +13 -10
  240. data/lib/sequel/model/default_inflections.rb +3 -1
  241. data/lib/sequel/model/errors.rb +3 -3
  242. data/lib/sequel/model/exceptions.rb +12 -12
  243. data/lib/sequel/model/inflections.rb +8 -19
  244. data/lib/sequel/model/plugins.rb +111 -0
  245. data/lib/sequel/plugins/accessed_columns.rb +2 -0
  246. data/lib/sequel/plugins/active_model.rb +32 -7
  247. data/lib/sequel/plugins/after_initialize.rb +3 -1
  248. data/lib/sequel/plugins/association_dependencies.rb +27 -18
  249. data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
  250. data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
  251. data/lib/sequel/plugins/association_pks.rb +181 -83
  252. data/lib/sequel/plugins/association_proxies.rb +33 -9
  253. data/lib/sequel/plugins/auto_validations.rb +58 -23
  254. data/lib/sequel/plugins/before_after_save.rb +8 -0
  255. data/lib/sequel/plugins/blacklist_security.rb +23 -12
  256. data/lib/sequel/plugins/boolean_readers.rb +9 -6
  257. data/lib/sequel/plugins/boolean_subsets.rb +64 -0
  258. data/lib/sequel/plugins/caching.rb +27 -16
  259. data/lib/sequel/plugins/class_table_inheritance.rb +192 -94
  260. data/lib/sequel/plugins/column_conflicts.rb +18 -3
  261. data/lib/sequel/plugins/column_select.rb +9 -5
  262. data/lib/sequel/plugins/columns_updated.rb +42 -0
  263. data/lib/sequel/plugins/composition.rb +36 -24
  264. data/lib/sequel/plugins/constraint_validations.rb +37 -16
  265. data/lib/sequel/plugins/csv_serializer.rb +58 -35
  266. data/lib/sequel/plugins/dataset_associations.rb +60 -18
  267. data/lib/sequel/plugins/def_dataset_method.rb +90 -0
  268. data/lib/sequel/plugins/defaults_setter.rb +74 -13
  269. data/lib/sequel/plugins/delay_add_association.rb +4 -1
  270. data/lib/sequel/plugins/dirty.rb +65 -24
  271. data/lib/sequel/plugins/eager_each.rb +27 -3
  272. data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
  273. data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
  274. data/lib/sequel/plugins/error_splitter.rb +19 -12
  275. data/lib/sequel/plugins/finder.rb +246 -0
  276. data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
  277. data/lib/sequel/plugins/force_encoding.rb +9 -12
  278. data/lib/sequel/plugins/hook_class_methods.rb +39 -54
  279. data/lib/sequel/plugins/input_transformer.rb +20 -10
  280. data/lib/sequel/plugins/insert_conflict.rb +72 -0
  281. data/lib/sequel/plugins/insert_returning_select.rb +4 -2
  282. data/lib/sequel/plugins/instance_filters.rb +12 -8
  283. data/lib/sequel/plugins/instance_hooks.rb +36 -17
  284. data/lib/sequel/plugins/instance_specific_default.rb +113 -0
  285. data/lib/sequel/plugins/inverted_subsets.rb +24 -13
  286. data/lib/sequel/plugins/json_serializer.rb +123 -47
  287. data/lib/sequel/plugins/lazy_attributes.rb +20 -14
  288. data/lib/sequel/plugins/list.rb +40 -26
  289. data/lib/sequel/plugins/many_through_many.rb +28 -12
  290. data/lib/sequel/plugins/modification_detection.rb +17 -5
  291. data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -5
  292. data/lib/sequel/plugins/nested_attributes.rb +55 -28
  293. data/lib/sequel/plugins/optimistic_locking.rb +5 -3
  294. data/lib/sequel/plugins/pg_array_associations.rb +52 -18
  295. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +348 -0
  296. data/lib/sequel/plugins/pg_row.rb +7 -51
  297. data/lib/sequel/plugins/prepared_statements.rb +53 -72
  298. data/lib/sequel/plugins/prepared_statements_safe.rb +13 -5
  299. data/lib/sequel/plugins/rcte_tree.rb +43 -63
  300. data/lib/sequel/plugins/serialization.rb +37 -44
  301. data/lib/sequel/plugins/serialization_modification_detection.rb +3 -1
  302. data/lib/sequel/plugins/sharding.rb +17 -10
  303. data/lib/sequel/plugins/single_table_inheritance.rb +62 -28
  304. data/lib/sequel/plugins/singular_table_names.rb +2 -0
  305. data/lib/sequel/plugins/skip_create_refresh.rb +5 -3
  306. data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
  307. data/lib/sequel/plugins/split_values.rb +13 -6
  308. data/lib/sequel/plugins/static_cache.rb +79 -53
  309. data/lib/sequel/plugins/static_cache_cache.rb +53 -0
  310. data/lib/sequel/plugins/string_stripper.rb +5 -3
  311. data/lib/sequel/plugins/subclasses.rb +20 -2
  312. data/lib/sequel/plugins/subset_conditions.rb +48 -0
  313. data/lib/sequel/plugins/table_select.rb +4 -2
  314. data/lib/sequel/plugins/tactical_eager_loading.rb +120 -6
  315. data/lib/sequel/plugins/throw_failures.rb +110 -0
  316. data/lib/sequel/plugins/timestamps.rb +22 -8
  317. data/lib/sequel/plugins/touch.rb +21 -8
  318. data/lib/sequel/plugins/tree.rb +57 -30
  319. data/lib/sequel/plugins/typecast_on_load.rb +14 -4
  320. data/lib/sequel/plugins/unlimited_update.rb +3 -7
  321. data/lib/sequel/plugins/update_or_create.rb +6 -4
  322. data/lib/sequel/plugins/update_primary_key.rb +3 -1
  323. data/lib/sequel/plugins/update_refresh.rb +28 -15
  324. data/lib/sequel/plugins/uuid.rb +70 -0
  325. data/lib/sequel/plugins/validate_associated.rb +20 -0
  326. data/lib/sequel/plugins/validation_class_methods.rb +40 -19
  327. data/lib/sequel/plugins/validation_contexts.rb +49 -0
  328. data/lib/sequel/plugins/validation_helpers.rb +49 -31
  329. data/lib/sequel/plugins/whitelist_security.rb +122 -0
  330. data/lib/sequel/plugins/xml_serializer.rb +31 -30
  331. data/lib/sequel/sql.rb +479 -329
  332. data/lib/sequel/timezones.rb +62 -32
  333. data/lib/sequel/version.rb +10 -3
  334. metadata +177 -477
  335. data/Rakefile +0 -165
  336. data/doc/active_record.rdoc +0 -912
  337. data/doc/release_notes/1.0.txt +0 -38
  338. data/doc/release_notes/1.1.txt +0 -143
  339. data/doc/release_notes/1.3.txt +0 -101
  340. data/doc/release_notes/1.4.0.txt +0 -53
  341. data/doc/release_notes/1.5.0.txt +0 -155
  342. data/doc/release_notes/2.0.0.txt +0 -298
  343. data/doc/release_notes/2.1.0.txt +0 -271
  344. data/doc/release_notes/2.10.0.txt +0 -328
  345. data/doc/release_notes/2.11.0.txt +0 -215
  346. data/doc/release_notes/2.12.0.txt +0 -534
  347. data/doc/release_notes/2.2.0.txt +0 -253
  348. data/doc/release_notes/2.3.0.txt +0 -88
  349. data/doc/release_notes/2.4.0.txt +0 -106
  350. data/doc/release_notes/2.5.0.txt +0 -137
  351. data/doc/release_notes/2.6.0.txt +0 -157
  352. data/doc/release_notes/2.7.0.txt +0 -166
  353. data/doc/release_notes/2.8.0.txt +0 -171
  354. data/doc/release_notes/2.9.0.txt +0 -97
  355. data/doc/release_notes/3.0.0.txt +0 -221
  356. data/doc/release_notes/3.1.0.txt +0 -406
  357. data/doc/release_notes/3.10.0.txt +0 -286
  358. data/doc/release_notes/3.11.0.txt +0 -254
  359. data/doc/release_notes/3.12.0.txt +0 -304
  360. data/doc/release_notes/3.13.0.txt +0 -210
  361. data/doc/release_notes/3.14.0.txt +0 -118
  362. data/doc/release_notes/3.15.0.txt +0 -78
  363. data/doc/release_notes/3.16.0.txt +0 -45
  364. data/doc/release_notes/3.17.0.txt +0 -58
  365. data/doc/release_notes/3.18.0.txt +0 -120
  366. data/doc/release_notes/3.19.0.txt +0 -67
  367. data/doc/release_notes/3.2.0.txt +0 -268
  368. data/doc/release_notes/3.20.0.txt +0 -41
  369. data/doc/release_notes/3.21.0.txt +0 -87
  370. data/doc/release_notes/3.22.0.txt +0 -39
  371. data/doc/release_notes/3.23.0.txt +0 -172
  372. data/doc/release_notes/3.24.0.txt +0 -420
  373. data/doc/release_notes/3.25.0.txt +0 -88
  374. data/doc/release_notes/3.26.0.txt +0 -88
  375. data/doc/release_notes/3.27.0.txt +0 -82
  376. data/doc/release_notes/3.28.0.txt +0 -304
  377. data/doc/release_notes/3.29.0.txt +0 -459
  378. data/doc/release_notes/3.3.0.txt +0 -192
  379. data/doc/release_notes/3.30.0.txt +0 -135
  380. data/doc/release_notes/3.31.0.txt +0 -146
  381. data/doc/release_notes/3.32.0.txt +0 -202
  382. data/doc/release_notes/3.33.0.txt +0 -157
  383. data/doc/release_notes/3.34.0.txt +0 -671
  384. data/doc/release_notes/3.35.0.txt +0 -144
  385. data/doc/release_notes/3.36.0.txt +0 -245
  386. data/doc/release_notes/3.37.0.txt +0 -338
  387. data/doc/release_notes/3.38.0.txt +0 -234
  388. data/doc/release_notes/3.39.0.txt +0 -237
  389. data/doc/release_notes/3.4.0.txt +0 -325
  390. data/doc/release_notes/3.40.0.txt +0 -73
  391. data/doc/release_notes/3.41.0.txt +0 -155
  392. data/doc/release_notes/3.42.0.txt +0 -74
  393. data/doc/release_notes/3.43.0.txt +0 -105
  394. data/doc/release_notes/3.44.0.txt +0 -152
  395. data/doc/release_notes/3.45.0.txt +0 -179
  396. data/doc/release_notes/3.46.0.txt +0 -122
  397. data/doc/release_notes/3.47.0.txt +0 -270
  398. data/doc/release_notes/3.48.0.txt +0 -477
  399. data/doc/release_notes/3.5.0.txt +0 -510
  400. data/doc/release_notes/3.6.0.txt +0 -366
  401. data/doc/release_notes/3.7.0.txt +0 -179
  402. data/doc/release_notes/3.8.0.txt +0 -151
  403. data/doc/release_notes/3.9.0.txt +0 -233
  404. data/doc/release_notes/4.0.0.txt +0 -262
  405. data/doc/release_notes/4.1.0.txt +0 -85
  406. data/doc/release_notes/4.10.0.txt +0 -226
  407. data/doc/release_notes/4.11.0.txt +0 -147
  408. data/doc/release_notes/4.12.0.txt +0 -105
  409. data/doc/release_notes/4.13.0.txt +0 -169
  410. data/doc/release_notes/4.14.0.txt +0 -68
  411. data/doc/release_notes/4.15.0.txt +0 -56
  412. data/doc/release_notes/4.16.0.txt +0 -36
  413. data/doc/release_notes/4.17.0.txt +0 -38
  414. data/doc/release_notes/4.18.0.txt +0 -36
  415. data/doc/release_notes/4.19.0.txt +0 -45
  416. data/doc/release_notes/4.2.0.txt +0 -129
  417. data/doc/release_notes/4.20.0.txt +0 -79
  418. data/doc/release_notes/4.21.0.txt +0 -94
  419. data/doc/release_notes/4.22.0.txt +0 -72
  420. data/doc/release_notes/4.23.0.txt +0 -65
  421. data/doc/release_notes/4.24.0.txt +0 -99
  422. data/doc/release_notes/4.25.0.txt +0 -181
  423. data/doc/release_notes/4.26.0.txt +0 -44
  424. data/doc/release_notes/4.3.0.txt +0 -40
  425. data/doc/release_notes/4.4.0.txt +0 -92
  426. data/doc/release_notes/4.5.0.txt +0 -34
  427. data/doc/release_notes/4.6.0.txt +0 -30
  428. data/doc/release_notes/4.7.0.txt +0 -103
  429. data/doc/release_notes/4.8.0.txt +0 -175
  430. data/doc/release_notes/4.9.0.txt +0 -190
  431. data/lib/sequel/adapters/cubrid.rb +0 -142
  432. data/lib/sequel/adapters/do.rb +0 -156
  433. data/lib/sequel/adapters/do/mysql.rb +0 -64
  434. data/lib/sequel/adapters/do/postgres.rb +0 -42
  435. data/lib/sequel/adapters/do/sqlite3.rb +0 -40
  436. data/lib/sequel/adapters/jdbc/as400.rb +0 -82
  437. data/lib/sequel/adapters/jdbc/cubrid.rb +0 -62
  438. data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -34
  439. data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -31
  440. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -31
  441. data/lib/sequel/adapters/odbc/progress.rb +0 -8
  442. data/lib/sequel/adapters/shared/cubrid.rb +0 -243
  443. data/lib/sequel/adapters/shared/firebird.rb +0 -245
  444. data/lib/sequel/adapters/shared/informix.rb +0 -52
  445. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +0 -150
  446. data/lib/sequel/adapters/shared/progress.rb +0 -38
  447. data/lib/sequel/adapters/swift.rb +0 -158
  448. data/lib/sequel/adapters/swift/mysql.rb +0 -47
  449. data/lib/sequel/adapters/swift/postgres.rb +0 -45
  450. data/lib/sequel/adapters/swift/sqlite.rb +0 -47
  451. data/lib/sequel/adapters/utils/pg_types.rb +0 -68
  452. data/lib/sequel/dataset/mutation.rb +0 -109
  453. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -3
  454. data/lib/sequel/extensions/filter_having.rb +0 -59
  455. data/lib/sequel/extensions/hash_aliases.rb +0 -45
  456. data/lib/sequel/extensions/meta_def.rb +0 -31
  457. data/lib/sequel/extensions/query_literals.rb +0 -80
  458. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -22
  459. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -118
  460. data/lib/sequel/extensions/set_overrides.rb +0 -72
  461. data/lib/sequel/no_core_ext.rb +0 -1
  462. data/lib/sequel/plugins/association_autoreloading.rb +0 -7
  463. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -7
  464. data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -78
  465. data/lib/sequel/plugins/prepared_statements_associations.rb +0 -117
  466. data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -59
  467. data/lib/sequel/plugins/schema.rb +0 -80
  468. data/lib/sequel/plugins/scissors.rb +0 -33
  469. data/spec/adapters/db2_spec.rb +0 -160
  470. data/spec/adapters/firebird_spec.rb +0 -411
  471. data/spec/adapters/informix_spec.rb +0 -100
  472. data/spec/adapters/mssql_spec.rb +0 -706
  473. data/spec/adapters/mysql_spec.rb +0 -1287
  474. data/spec/adapters/oracle_spec.rb +0 -313
  475. data/spec/adapters/postgres_spec.rb +0 -3725
  476. data/spec/adapters/spec_helper.rb +0 -43
  477. data/spec/adapters/sqlanywhere_spec.rb +0 -170
  478. data/spec/adapters/sqlite_spec.rb +0 -653
  479. data/spec/bin_spec.rb +0 -254
  480. data/spec/core/connection_pool_spec.rb +0 -1016
  481. data/spec/core/database_spec.rb +0 -2531
  482. data/spec/core/dataset_spec.rb +0 -5098
  483. data/spec/core/deprecated_spec.rb +0 -70
  484. data/spec/core/expression_filters_spec.rb +0 -1243
  485. data/spec/core/mock_adapter_spec.rb +0 -462
  486. data/spec/core/object_graph_spec.rb +0 -303
  487. data/spec/core/placeholder_literalizer_spec.rb +0 -163
  488. data/spec/core/schema_generator_spec.rb +0 -179
  489. data/spec/core/schema_spec.rb +0 -1659
  490. data/spec/core/spec_helper.rb +0 -34
  491. data/spec/core/version_spec.rb +0 -7
  492. data/spec/core_extensions_spec.rb +0 -699
  493. data/spec/extensions/accessed_columns_spec.rb +0 -51
  494. data/spec/extensions/active_model_spec.rb +0 -123
  495. data/spec/extensions/after_initialize_spec.rb +0 -24
  496. data/spec/extensions/arbitrary_servers_spec.rb +0 -109
  497. data/spec/extensions/association_dependencies_spec.rb +0 -117
  498. data/spec/extensions/association_pks_spec.rb +0 -365
  499. data/spec/extensions/association_proxies_spec.rb +0 -86
  500. data/spec/extensions/auto_validations_spec.rb +0 -192
  501. data/spec/extensions/blacklist_security_spec.rb +0 -88
  502. data/spec/extensions/blank_spec.rb +0 -69
  503. data/spec/extensions/boolean_readers_spec.rb +0 -93
  504. data/spec/extensions/caching_spec.rb +0 -270
  505. data/spec/extensions/class_table_inheritance_spec.rb +0 -420
  506. data/spec/extensions/column_conflicts_spec.rb +0 -60
  507. data/spec/extensions/column_select_spec.rb +0 -108
  508. data/spec/extensions/columns_introspection_spec.rb +0 -91
  509. data/spec/extensions/composition_spec.rb +0 -242
  510. data/spec/extensions/connection_validator_spec.rb +0 -120
  511. data/spec/extensions/constraint_validations_plugin_spec.rb +0 -274
  512. data/spec/extensions/constraint_validations_spec.rb +0 -325
  513. data/spec/extensions/core_refinements_spec.rb +0 -519
  514. data/spec/extensions/csv_serializer_spec.rb +0 -173
  515. data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
  516. data/spec/extensions/dataset_associations_spec.rb +0 -311
  517. data/spec/extensions/dataset_source_alias_spec.rb +0 -51
  518. data/spec/extensions/date_arithmetic_spec.rb +0 -150
  519. data/spec/extensions/defaults_setter_spec.rb +0 -101
  520. data/spec/extensions/delay_add_association_spec.rb +0 -52
  521. data/spec/extensions/dirty_spec.rb +0 -180
  522. data/spec/extensions/eager_each_spec.rb +0 -42
  523. data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
  524. data/spec/extensions/error_splitter_spec.rb +0 -18
  525. data/spec/extensions/error_sql_spec.rb +0 -20
  526. data/spec/extensions/eval_inspect_spec.rb +0 -73
  527. data/spec/extensions/filter_having_spec.rb +0 -40
  528. data/spec/extensions/force_encoding_spec.rb +0 -114
  529. data/spec/extensions/from_block_spec.rb +0 -21
  530. data/spec/extensions/graph_each_spec.rb +0 -109
  531. data/spec/extensions/hash_aliases_spec.rb +0 -24
  532. data/spec/extensions/hook_class_methods_spec.rb +0 -429
  533. data/spec/extensions/inflector_spec.rb +0 -183
  534. data/spec/extensions/input_transformer_spec.rb +0 -54
  535. data/spec/extensions/insert_returning_select_spec.rb +0 -46
  536. data/spec/extensions/instance_filters_spec.rb +0 -79
  537. data/spec/extensions/instance_hooks_spec.rb +0 -276
  538. data/spec/extensions/inverted_subsets_spec.rb +0 -33
  539. data/spec/extensions/json_serializer_spec.rb +0 -291
  540. data/spec/extensions/lazy_attributes_spec.rb +0 -170
  541. data/spec/extensions/list_spec.rb +0 -267
  542. data/spec/extensions/looser_typecasting_spec.rb +0 -43
  543. data/spec/extensions/many_through_many_spec.rb +0 -2172
  544. data/spec/extensions/meta_def_spec.rb +0 -21
  545. data/spec/extensions/migration_spec.rb +0 -712
  546. data/spec/extensions/modification_detection_spec.rb +0 -80
  547. data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -91
  548. data/spec/extensions/named_timezones_spec.rb +0 -108
  549. data/spec/extensions/nested_attributes_spec.rb +0 -697
  550. data/spec/extensions/null_dataset_spec.rb +0 -85
  551. data/spec/extensions/optimistic_locking_spec.rb +0 -128
  552. data/spec/extensions/pagination_spec.rb +0 -118
  553. data/spec/extensions/pg_array_associations_spec.rb +0 -736
  554. data/spec/extensions/pg_array_ops_spec.rb +0 -143
  555. data/spec/extensions/pg_array_spec.rb +0 -395
  556. data/spec/extensions/pg_enum_spec.rb +0 -92
  557. data/spec/extensions/pg_hstore_ops_spec.rb +0 -236
  558. data/spec/extensions/pg_hstore_spec.rb +0 -206
  559. data/spec/extensions/pg_inet_ops_spec.rb +0 -101
  560. data/spec/extensions/pg_inet_spec.rb +0 -52
  561. data/spec/extensions/pg_interval_spec.rb +0 -76
  562. data/spec/extensions/pg_json_ops_spec.rb +0 -229
  563. data/spec/extensions/pg_json_spec.rb +0 -218
  564. data/spec/extensions/pg_loose_count_spec.rb +0 -17
  565. data/spec/extensions/pg_range_ops_spec.rb +0 -58
  566. data/spec/extensions/pg_range_spec.rb +0 -404
  567. data/spec/extensions/pg_row_ops_spec.rb +0 -60
  568. data/spec/extensions/pg_row_plugin_spec.rb +0 -62
  569. data/spec/extensions/pg_row_spec.rb +0 -360
  570. data/spec/extensions/pg_static_cache_updater_spec.rb +0 -92
  571. data/spec/extensions/pg_typecast_on_load_spec.rb +0 -63
  572. data/spec/extensions/prepared_statements_associations_spec.rb +0 -159
  573. data/spec/extensions/prepared_statements_safe_spec.rb +0 -61
  574. data/spec/extensions/prepared_statements_spec.rb +0 -103
  575. data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -31
  576. data/spec/extensions/pretty_table_spec.rb +0 -92
  577. data/spec/extensions/query_literals_spec.rb +0 -183
  578. data/spec/extensions/query_spec.rb +0 -102
  579. data/spec/extensions/rcte_tree_spec.rb +0 -392
  580. data/spec/extensions/round_timestamps_spec.rb +0 -43
  581. data/spec/extensions/schema_caching_spec.rb +0 -41
  582. data/spec/extensions/schema_dumper_spec.rb +0 -789
  583. data/spec/extensions/schema_spec.rb +0 -117
  584. data/spec/extensions/scissors_spec.rb +0 -26
  585. data/spec/extensions/select_remove_spec.rb +0 -38
  586. data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -101
  587. data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
  588. data/spec/extensions/serialization_spec.rb +0 -362
  589. data/spec/extensions/server_block_spec.rb +0 -90
  590. data/spec/extensions/set_overrides_spec.rb +0 -61
  591. data/spec/extensions/sharding_spec.rb +0 -198
  592. data/spec/extensions/shared_caching_spec.rb +0 -175
  593. data/spec/extensions/single_table_inheritance_spec.rb +0 -297
  594. data/spec/extensions/singular_table_names_spec.rb +0 -22
  595. data/spec/extensions/skip_create_refresh_spec.rb +0 -17
  596. data/spec/extensions/spec_helper.rb +0 -71
  597. data/spec/extensions/split_array_nil_spec.rb +0 -24
  598. data/spec/extensions/split_values_spec.rb +0 -22
  599. data/spec/extensions/sql_expr_spec.rb +0 -60
  600. data/spec/extensions/static_cache_spec.rb +0 -361
  601. data/spec/extensions/string_date_time_spec.rb +0 -95
  602. data/spec/extensions/string_stripper_spec.rb +0 -68
  603. data/spec/extensions/subclasses_spec.rb +0 -66
  604. data/spec/extensions/table_select_spec.rb +0 -71
  605. data/spec/extensions/tactical_eager_loading_spec.rb +0 -82
  606. data/spec/extensions/thread_local_timezones_spec.rb +0 -67
  607. data/spec/extensions/timestamps_spec.rb +0 -175
  608. data/spec/extensions/to_dot_spec.rb +0 -154
  609. data/spec/extensions/touch_spec.rb +0 -203
  610. data/spec/extensions/tree_spec.rb +0 -274
  611. data/spec/extensions/typecast_on_load_spec.rb +0 -80
  612. data/spec/extensions/unlimited_update_spec.rb +0 -20
  613. data/spec/extensions/update_or_create_spec.rb +0 -87
  614. data/spec/extensions/update_primary_key_spec.rb +0 -100
  615. data/spec/extensions/update_refresh_spec.rb +0 -53
  616. data/spec/extensions/validate_associated_spec.rb +0 -52
  617. data/spec/extensions/validation_class_methods_spec.rb +0 -1027
  618. data/spec/extensions/validation_helpers_spec.rb +0 -541
  619. data/spec/extensions/xml_serializer_spec.rb +0 -207
  620. data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
  621. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
  622. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  623. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  624. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
  625. data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
  626. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
  627. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
  628. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
  629. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
  630. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
  631. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
  632. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
  633. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
  634. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  635. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
  636. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
  637. data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
  638. data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
  639. data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
  640. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  641. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
  642. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  643. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
  644. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  645. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
  646. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
  647. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  648. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  649. data/spec/files/reversible_migrations/001_reversible.rb +0 -5
  650. data/spec/files/reversible_migrations/002_reversible.rb +0 -5
  651. data/spec/files/reversible_migrations/003_reversible.rb +0 -5
  652. data/spec/files/reversible_migrations/004_reversible.rb +0 -5
  653. data/spec/files/reversible_migrations/005_reversible.rb +0 -10
  654. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
  655. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
  656. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
  657. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
  658. data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
  659. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
  660. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
  661. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
  662. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
  663. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
  664. data/spec/guards_helper.rb +0 -55
  665. data/spec/integration/associations_test.rb +0 -2454
  666. data/spec/integration/database_test.rb +0 -113
  667. data/spec/integration/dataset_test.rb +0 -1808
  668. data/spec/integration/eager_loader_test.rb +0 -687
  669. data/spec/integration/migrator_test.rb +0 -240
  670. data/spec/integration/model_test.rb +0 -226
  671. data/spec/integration/plugin_test.rb +0 -2240
  672. data/spec/integration/prepared_statement_test.rb +0 -467
  673. data/spec/integration/schema_test.rb +0 -817
  674. data/spec/integration/spec_helper.rb +0 -48
  675. data/spec/integration/timezone_test.rb +0 -86
  676. data/spec/integration/transaction_test.rb +0 -374
  677. data/spec/integration/type_test.rb +0 -133
  678. data/spec/model/association_reflection_spec.rb +0 -525
  679. data/spec/model/associations_spec.rb +0 -4426
  680. data/spec/model/base_spec.rb +0 -759
  681. data/spec/model/class_dataset_methods_spec.rb +0 -146
  682. data/spec/model/dataset_methods_spec.rb +0 -149
  683. data/spec/model/eager_loading_spec.rb +0 -2137
  684. data/spec/model/hooks_spec.rb +0 -604
  685. data/spec/model/inflector_spec.rb +0 -26
  686. data/spec/model/model_spec.rb +0 -982
  687. data/spec/model/plugins_spec.rb +0 -299
  688. data/spec/model/record_spec.rb +0 -2147
  689. data/spec/model/spec_helper.rb +0 -46
  690. data/spec/model/validations_spec.rb +0 -193
  691. data/spec/sequel_coverage.rb +0 -15
  692. data/spec/spec_config.rb +0 -10
@@ -1,52 +1,26 @@
1
+ # frozen-string-literal: true
2
+
1
3
  module Sequel
2
4
  module SqlAnywhere
3
-
4
- @convert_smallint_to_bool = true
5
-
6
- class << self
7
- # Whether to convert smallint values to bool, false by default.
8
- # Can also be overridden per dataset.
9
- attr_accessor :convert_smallint_to_bool
10
- end
5
+ Sequel::Database.set_shared_adapter_scheme(:sqlanywhere, self)
11
6
 
12
7
  module DatabaseMethods
13
- extend Sequel::Database::ResetIdentifierMangling
14
-
15
8
  attr_reader :conversion_procs
16
9
 
17
- # Override the default SqlAnywhere.convert_smallint_to_bool setting for this database.
18
- attr_writer :convert_smallint_to_bool
19
-
20
- AUTO_INCREMENT = 'IDENTITY'.freeze
21
- SQL_BEGIN = "BEGIN TRANSACTION".freeze
22
- SQL_COMMIT = "COMMIT TRANSACTION".freeze
23
- SQL_ROLLBACK = "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION".freeze
24
- TEMPORARY = "GLOBAL TEMPORARY ".freeze
25
- SMALLINT_RE = /smallint/i.freeze
26
- DECIMAL_TYPE_RE = /numeric/io
27
-
28
- # Whether to convert smallint to boolean arguments for this dataset.
29
- # Defaults to the SqlAnywhere module setting.
30
- def convert_smallint_to_bool
31
- defined?(@convert_smallint_to_bool) ? @convert_smallint_to_bool : (@convert_smallint_to_bool = ::Sequel::SqlAnywhere.convert_smallint_to_bool)
32
- end
10
+ # Set whether to convert smallint type to boolean for this Database instance
11
+ attr_accessor :convert_smallint_to_bool
33
12
 
34
- # Sysbase Server uses the :sqlanywhere type.
35
13
  def database_type
36
14
  :sqlanywhere
37
15
  end
38
16
 
39
- def to_application_timestamp_sa(v)
40
- to_application_timestamp(v.to_s) if v
17
+ def freeze
18
+ @conversion_procs.freeze
19
+ super
41
20
  end
42
21
 
43
- # Convert smallint type to boolean if convert_smallint_to_bool is true
44
- def schema_column_type(db_type)
45
- if convert_smallint_to_bool && db_type =~ SMALLINT_RE
46
- :boolean
47
- else
48
- super
49
- end
22
+ def to_application_timestamp_sa(v)
23
+ to_application_timestamp(v.to_s) if v
50
24
  end
51
25
 
52
26
  def schema_parse_table(table, opts)
@@ -54,15 +28,15 @@ module Sequel
54
28
  im = input_identifier_meth(opts[:dataset])
55
29
  metadata_dataset.
56
30
  from{sa_describe_query("select * from #{im.call(table)}").as(:a)}.
57
- join(:syscolumn___b, :table_id=>:base_table_id, :column_id=>:base_column_id).
58
- order(:a__column_number).
31
+ join(Sequel[:syscolumn].as(:b), :table_id=>:base_table_id, :column_id=>:base_column_id).
32
+ order{a[:column_number]}.
59
33
  map do |row|
60
34
  auto_increment = row.delete(:is_autoincrement)
61
35
  row[:auto_increment] = auto_increment == 1 || auto_increment == true
62
36
  row[:primary_key] = row.delete(:pkey) == 'Y'
63
- row[:allow_null] = row[:nulls_allowed].is_a?(Fixnum) ? row.delete(:nulls_allowed) == 1 : row.delete(:nulls_allowed)
37
+ row[:allow_null] = row[:nulls_allowed].is_a?(Integer) ? row.delete(:nulls_allowed) == 1 : row.delete(:nulls_allowed)
64
38
  row[:db_type] = row.delete(:domain_name)
65
- row[:type] = if row[:db_type] =~ DECIMAL_TYPE_RE and (row[:scale].is_a?(Fixnum) ? row[:scale] == 0 : !row[:scale])
39
+ row[:type] = if row[:db_type] =~ /numeric/i and (row[:scale].is_a?(Integer) ? row[:scale] == 0 : !row[:scale])
66
40
  :integer
67
41
  else
68
42
  schema_column_type(row[:db_type])
@@ -75,13 +49,18 @@ module Sequel
75
49
  def indexes(table, opts = OPTS)
76
50
  m = output_identifier_meth
77
51
  im = input_identifier_meth
52
+ table = table.value if table.is_a?(Sequel::SQL::Identifier)
78
53
  indexes = {}
79
54
  metadata_dataset.
80
- from(:dbo__sysobjects___z).
81
- select(:z__name___table_name, :i__name___index_name, :si__indextype___type, :si__colnames___columns).
82
- join(:dbo__sysindexes___i, :id___i=> :id___z).
83
- join(:sys__sysindexes___si, :iname=> :name___i).
84
- where(:z__type => 'U', :table_name=>im.call(table)).
55
+ from(Sequel[:dbo][:sysobjects].as(:z)).
56
+ select{[
57
+ z[:name].as(:table_name),
58
+ i[:name].as(:index_name),
59
+ si[:indextype].as(:type),
60
+ si[:colnames].as(:columns)]}.
61
+ join(Sequel[:dbo][:sysindexes].as(:i), :id=>:id).
62
+ join(Sequel[:sys][:sysindexes].as(:si), :iname=> :name).
63
+ where{{z[:type] => 'U', :table_name=>im.call(table)}}.
85
64
  each do |r|
86
65
  indexes[m.call(r[:index_name])] =
87
66
  {:unique=>(r[:type].downcase=='unique'),
@@ -95,11 +74,16 @@ module Sequel
95
74
  im = input_identifier_meth
96
75
  fk_indexes = {}
97
76
  metadata_dataset.
98
- from(:sys__sysforeignkey___fk).
99
- select(:fk__role___name, :fks__columns___column_map, :si__indextype___type, :si__colnames___columns, :fks__primary_tname___table_name).
100
- join(:sys__sysforeignkeys___fks, :role => :role).
101
- join_table(:inner, :sys__sysindexes___si, [:iname=> :fk__role], {:implicit_qualifier => :fk}).
102
- where(:fks__foreign_tname=>im.call(table)).
77
+ from{sys[:sysforeignkey].as(:fk)}.
78
+ select{[
79
+ fk[:role].as(:name),
80
+ fks[:columns].as(:column_map),
81
+ si[:indextype].as(:type),
82
+ si[:colnames].as(:columns),
83
+ fks[:primary_tname].as(:table_name)]}.
84
+ join(Sequel[:sys][:sysforeignkeys].as(:fks), :role => :role).
85
+ join(Sequel[:sys][:sysindexes].as(:si), {:iname => Sequel[:fk][:role]}, {:implicit_qualifier => :fk}).
86
+ where{{fks[:foreign_tname]=>im.call(table)}}.
103
87
  each do |r|
104
88
  unless r[:type].downcase == 'primary key'
105
89
  fk_indexes[r[:name]] =
@@ -136,27 +120,28 @@ module Sequel
136
120
 
137
121
  # Sybase uses the IDENTITY column for autoincrementing columns.
138
122
  def auto_increment_sql
139
- AUTO_INCREMENT
123
+ 'IDENTITY'
140
124
  end
141
125
 
142
- # SQL fragment for marking a table as temporary
126
+ # Sybase does not allow adding primary key constraints to NULLable columns.
127
+ def can_add_primary_key_constraint_on_nullable_columns?
128
+ false
129
+ end
130
+
143
131
  def temporary_table_sql
144
- TEMPORARY
132
+ "GLOBAL TEMPORARY "
145
133
  end
146
134
 
147
- # SQL to BEGIN a transaction.
148
135
  def begin_transaction_sql
149
- SQL_BEGIN
136
+ "BEGIN TRANSACTION"
150
137
  end
151
138
 
152
- # SQL to ROLLBACK a transaction.
153
139
  def rollback_transaction_sql
154
- SQL_ROLLBACK
140
+ "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION"
155
141
  end
156
142
 
157
- # SQL to COMMIT a transaction.
158
143
  def commit_transaction_sql
159
- SQL_COMMIT
144
+ "COMMIT TRANSACTION"
160
145
  end
161
146
 
162
147
  # Sybase has both datetime and timestamp classes, most people are going
@@ -165,12 +150,6 @@ module Sequel
165
150
  :datetime
166
151
  end
167
152
 
168
- # Sybase has both datetime and timestamp classes, most people are going
169
- # to want datetime
170
- def type_literal_generic_time(column)
171
- column[:only_time] ? :time : :datetime
172
- end
173
-
174
153
  # Sybase doesn't have a true boolean class, so it uses integer
175
154
  def type_literal_generic_trueclass(column)
176
155
  :smallint
@@ -181,7 +160,6 @@ module Sequel
181
160
  :image
182
161
  end
183
162
 
184
- # Sybase specific syntax for altering tables.
185
163
  def alter_table_sql(table, op)
186
164
  case op[:op]
187
165
  when :add_column
@@ -229,12 +207,21 @@ module Sequel
229
207
  "ALTER TABLE #{quote_schema_table(name)} RENAME #{quote_schema_table(new_name)}"
230
208
  end
231
209
 
210
+ # Convert smallint type to boolean if convert_smallint_to_bool is true
211
+ def schema_column_type(db_type)
212
+ if convert_smallint_to_bool && db_type =~ /smallint/i
213
+ :boolean
214
+ else
215
+ super
216
+ end
217
+ end
218
+
232
219
  def tables_and_views(type, opts=OPTS)
233
220
  m = output_identifier_meth
234
221
  metadata_dataset.
235
- from(:sysobjects___a).
236
- where(:a__type=>type).
237
- select_map(:a__name).
222
+ from{sysobjects.as(:a)}.
223
+ where{{a[:type]=>type}}.
224
+ select_map{a[:name]}.
238
225
  map{|n| m.call(n)}
239
226
  end
240
227
 
@@ -245,42 +232,22 @@ module Sequel
245
232
  end
246
233
 
247
234
  module DatasetMethods
248
- BOOL_TRUE = '1'.freeze
249
- BOOL_FALSE = '0'.freeze
250
- WILDCARD = LiteralString.new('%').freeze
251
- TOP = " TOP ".freeze
252
- START_AT = " START AT ".freeze
253
- SQL_WITH_RECURSIVE = "WITH RECURSIVE ".freeze
254
- DATE_FUNCTION = 'today()'.freeze
255
- NOW_FUNCTION = 'now()'.freeze
256
- DATEPART = 'datepart'.freeze
257
- REGEXP = 'REGEXP'.freeze
258
- NOT_REGEXP = 'NOT REGEXP'.freeze
259
- APOS = Dataset::APOS
260
- APOS_RE = Dataset::APOS_RE
261
- DOUBLE_APOS = Dataset::DOUBLE_APOS
262
- BACKSLASH_RE = /\\/.freeze
263
- QUAD_BACKSLASH = "\\\\\\\\".freeze
264
- BLOB_START = "0x".freeze
265
- HSTAR = "H*".freeze
266
- CROSS_APPLY = 'CROSS APPLY'.freeze
267
- OUTER_APPLY = 'OUTER APPLY'.freeze
268
- ONLY_OFFSET = " TOP 2147483647".freeze
269
-
270
- Dataset.def_sql_method(self, :insert, %w'with insert into columns values')
271
- Dataset.def_sql_method(self, :select, %w'with select distinct limit columns into from join where group having order compounds lock')
235
+ Dataset.def_sql_method(self, :insert, %w'insert into columns values')
236
+ Dataset.def_sql_method(self, :select, %w'with select distinct limit columns into from join where group having window compounds order lock')
272
237
 
273
238
  # Whether to convert smallint to boolean arguments for this dataset.
274
- # Defaults to the SqlAnywhere module setting.
239
+ # Defaults to the IBMDB module setting.
275
240
  def convert_smallint_to_bool
276
- defined?(@convert_smallint_to_bool) ? @convert_smallint_to_bool : (@convert_smallint_to_bool = @db.convert_smallint_to_bool)
241
+ opts.has_key?(:convert_smallint_to_bool) ? opts[:convert_smallint_to_bool] : db.convert_smallint_to_bool
277
242
  end
278
243
 
279
- # Override the default SqlAnywhere.convert_smallint_to_bool setting for this dataset.
280
- attr_writer :convert_smallint_to_bool
244
+ # Return a cloned dataset with the convert_smallint_to_bool option set.
245
+ def with_convert_smallint_to_bool(v)
246
+ clone(:convert_smallint_to_bool=>v)
247
+ end
281
248
 
282
249
  def supports_cte?(type=:select)
283
- type == :select || type == :insert
250
+ type == :select
284
251
  end
285
252
 
286
253
  # SQLAnywhere supports GROUPING SETS
@@ -308,6 +275,14 @@ module Sequel
308
275
  false
309
276
  end
310
277
 
278
+ def supports_window_clause?
279
+ true
280
+ end
281
+
282
+ def supports_window_functions?
283
+ true
284
+ end
285
+
311
286
  # Uses CROSS APPLY to join the given table into the current dataset.
312
287
  def cross_apply(table)
313
288
  join_table(:cross_apply, table)
@@ -318,7 +293,6 @@ module Sequel
318
293
  true
319
294
  end
320
295
 
321
- # SQLAnywhere uses + for string concatenation, and LIKE is case insensitive by default.
322
296
  def complex_expression_sql_append(sql, op, args)
323
297
  case op
324
298
  when :'||'
@@ -326,12 +300,12 @@ module Sequel
326
300
  when :<<, :>>
327
301
  complex_expression_emulate_append(sql, op, args)
328
302
  when :LIKE, :"NOT LIKE"
329
- sql << Sequel::Dataset::PAREN_OPEN
330
- literal_append(sql, args.at(0))
331
- sql << Sequel::Dataset::SPACE << (op == :LIKE ? REGEXP : NOT_REGEXP) << Sequel::Dataset::SPACE
332
- pattern = ''
303
+ sql << '('
304
+ literal_append(sql, args[0])
305
+ sql << (op == :LIKE ? ' REGEXP ' : ' NOT REGEXP ')
306
+ pattern = String.new
333
307
  last_c = ''
334
- args.at(1).each_char do |c|
308
+ args[1].each_char do |c|
335
309
  if c == '_' and not pattern.end_with?('\\') and last_c != '\\'
336
310
  pattern << '.'
337
311
  elsif c == '%' and not pattern.end_with?('\\') and last_c != '\\'
@@ -354,17 +328,17 @@ module Sequel
354
328
  end
355
329
  end
356
330
  literal_append(sql, pattern)
357
- sql << Sequel::Dataset::ESCAPE
358
- literal_append(sql, Sequel::Dataset::BACKSLASH)
359
- sql << Sequel::Dataset::PAREN_CLOSE
331
+ sql << " ESCAPE "
332
+ literal_append(sql, "\\")
333
+ sql << ')'
360
334
  when :ILIKE, :"NOT ILIKE"
361
335
  super(sql, (op == :ILIKE ? :LIKE : :"NOT LIKE"), args)
362
336
  when :extract
363
- sql << DATEPART + Sequel::Dataset::PAREN_OPEN
364
- literal_append(sql, args.at(0))
337
+ sql << 'datepart('
338
+ literal_append(sql, args[0])
365
339
  sql << ','
366
- literal_append(sql, args.at(1))
367
- sql << Sequel::Dataset::PAREN_CLOSE
340
+ literal_append(sql, args[1])
341
+ sql << ')'
368
342
  else
369
343
  super
370
344
  end
@@ -375,13 +349,13 @@ module Sequel
375
349
  string.gsub(/[\\%_\[]/){|m| "\\#{m}"}
376
350
  end
377
351
 
378
- # Use Date() and Now() for CURRENT_DATE and CURRENT_TIMESTAMP
352
+ # Use today() for CURRENT_DATE and now() for CURRENT_TIMESTAMP and CURRENT_TIME
379
353
  def constant_sql_append(sql, constant)
380
354
  case constant
381
355
  when :CURRENT_DATE
382
- sql << DATE_FUNCTION
356
+ sql << 'today()'
383
357
  when :CURRENT_TIMESTAMP, :CURRENT_TIME
384
- sql << NOW_FUNCTION
358
+ sql << 'now()'
385
359
  else
386
360
  super
387
361
  end
@@ -396,17 +370,17 @@ module Sequel
396
370
 
397
371
  # Use 1 for true on Sybase
398
372
  def literal_true
399
- BOOL_TRUE
373
+ '1'
400
374
  end
401
375
 
402
376
  # Use 0 for false on Sybase
403
377
  def literal_false
404
- BOOL_FALSE
378
+ '0'
405
379
  end
406
380
 
407
381
  # SQL fragment for String. Doubles \ and ' by default.
408
382
  def literal_string_append(sql, v)
409
- sql << APOS << v.gsub(BACKSLASH_RE, QUAD_BACKSLASH).gsub(APOS_RE, DOUBLE_APOS) << APOS
383
+ sql << "'" << v.gsub("\\", "\\\\\\\\").gsub("'", "''") << "'"
410
384
  end
411
385
 
412
386
  # SqlAnywhere uses a preceding X for hex escaping strings
@@ -414,7 +388,7 @@ module Sequel
414
388
  if v.empty?
415
389
  literal_append(sql, "")
416
390
  else
417
- sql << BLOB_START << v.unpack(HSTAR).first
391
+ sql << "0x" << v.unpack("H*").first
418
392
  end
419
393
  end
420
394
 
@@ -423,28 +397,32 @@ module Sequel
423
397
  :values
424
398
  end
425
399
 
400
+ # SQLAnywhere does not natively support NULLS FIRST/LAST.
401
+ def requires_emulating_nulls_first?
402
+ true
403
+ end
404
+
426
405
  def select_into_sql(sql)
427
406
  if i = @opts[:into]
428
- sql << Sequel::Dataset::INTO
407
+ sql << " INTO "
429
408
  identifier_append(sql, i)
430
409
  end
431
410
  end
432
411
 
433
- # Sybase uses TOP N for limit. For Sybase TOP (N) is used
434
- # to allow the limit to be a bound variable.
412
+ # Sybase uses TOP N for limit.
435
413
  def select_limit_sql(sql)
436
414
  l = @opts[:limit]
437
415
  o = @opts[:offset]
438
416
  if l || o
439
417
  if l
440
- sql << TOP
418
+ sql << " TOP "
441
419
  literal_append(sql, l)
442
420
  else
443
- sql << ONLY_OFFSET
421
+ sql << " TOP 2147483647"
444
422
  end
445
423
 
446
424
  if o
447
- sql << START_AT + "("
425
+ sql << " START AT ("
448
426
  literal_append(sql, o)
449
427
  sql << " + 1)"
450
428
  end
@@ -453,15 +431,15 @@ module Sequel
453
431
 
454
432
  # Use WITH RECURSIVE instead of WITH if any of the CTEs is recursive
455
433
  def select_with_sql_base
456
- opts[:with].any?{|w| w[:recursive]} ? SQL_WITH_RECURSIVE : super
434
+ opts[:with].any?{|w| w[:recursive]} ? "WITH RECURSIVE " : super
457
435
  end
458
436
 
459
437
  def join_type_sql(join_type)
460
438
  case join_type
461
439
  when :cross_apply
462
- CROSS_APPLY
440
+ 'CROSS APPLY'
463
441
  when :outer_apply
464
- OUTER_APPLY
442
+ 'OUTER APPLY'
465
443
  else
466
444
  super
467
445
  end
@@ -1,49 +1,46 @@
1
- Sequel.require 'adapters/utils/replace'
1
+ # frozen-string-literal: true
2
+
3
+ require_relative '../utils/replace'
4
+ require_relative '../utils/unmodified_identifiers'
2
5
 
3
6
  module Sequel
4
7
  module SQLite
8
+ Sequel::Database.set_shared_adapter_scheme(:sqlite, self)
9
+
10
+ def self.mock_adapter_setup(db)
11
+ db.instance_exec do
12
+ @sqlite_version = 30903
13
+
14
+ def schema_parse_table(*)
15
+ []
16
+ end
17
+ singleton_class.send(:private, :schema_parse_table)
18
+ end
19
+ end
20
+
5
21
  # No matter how you connect to SQLite, the following Database options
6
22
  # can be used to set PRAGMAs on connections in a thread-safe manner:
7
23
  # :auto_vacuum, :foreign_keys, :synchronous, and :temp_store.
8
24
  module DatabaseMethods
9
- extend Sequel::Database::ResetIdentifierMangling
25
+ include UnmodifiedIdentifiers::DatabaseMethods
10
26
 
11
27
  AUTO_VACUUM = [:none, :full, :incremental].freeze
12
- PRIMARY_KEY_INDEX_RE = /\Asqlite_autoindex_/.freeze
13
28
  SYNCHRONOUS = [:off, :normal, :full].freeze
14
- TABLES_FILTER = "type = 'table' AND NOT name = 'sqlite_sequence'".freeze
15
29
  TEMP_STORE = [:default, :file, :memory].freeze
16
- VIEWS_FILTER = "type = 'view'".freeze
17
30
  TRANSACTION_MODE = {
18
31
  :deferred => "BEGIN DEFERRED TRANSACTION".freeze,
19
32
  :immediate => "BEGIN IMMEDIATE TRANSACTION".freeze,
20
33
  :exclusive => "BEGIN EXCLUSIVE TRANSACTION".freeze,
21
- nil => Sequel::Database::SQL_BEGIN,
34
+ nil => "BEGIN".freeze
22
35
  }.freeze
23
36
 
24
37
  # Whether to use integers for booleans in the database. SQLite recommends
25
38
  # booleans be stored as integers, but historically Sequel has used 't'/'f'.
26
39
  attr_accessor :integer_booleans
27
40
 
28
- # A symbol signifying the value of the auto_vacuum PRAGMA.
29
- def auto_vacuum
30
- AUTO_VACUUM[pragma_get(:auto_vacuum).to_i]
31
- end
32
-
33
- # Set the auto_vacuum PRAGMA using the given symbol (:none, :full, or
34
- # :incremental). See pragma_set. Consider using the :auto_vacuum
35
- # Database option instead.
36
- def auto_vacuum=(value)
37
- value = AUTO_VACUUM.index(value) || (raise Error, "Invalid value for auto_vacuum option. Please specify one of :none, :full, :incremental.")
38
- pragma_set(:auto_vacuum, value)
39
- end
40
-
41
- # Set the case_sensitive_like PRAGMA using the given boolean value, if using
42
- # SQLite 3.2.3+. If not using 3.2.3+, no error is raised. See pragma_set.
43
- # Consider using the :case_sensitive_like Database option instead.
44
- def case_sensitive_like=(value)
45
- pragma_set(:case_sensitive_like, !!value ? 'on' : 'off') if sqlite_version >= 30203
46
- end
41
+ # Whether to keep CURRENT_TIMESTAMP and similar expressions in UTC. By
42
+ # default, the expressions are converted to localtime.
43
+ attr_accessor :current_timestamp_utc
47
44
 
48
45
  # A symbol signifying the value of the default transaction mode
49
46
  attr_reader :transaction_mode
@@ -62,17 +59,9 @@ module Sequel
62
59
  :sqlite
63
60
  end
64
61
 
65
- # Boolean signifying the value of the foreign_keys PRAGMA, or nil
66
- # if not using SQLite 3.6.19+.
67
- def foreign_keys
68
- pragma_get(:foreign_keys).to_i == 1 if sqlite_version >= 30619
69
- end
70
-
71
- # Set the foreign_keys PRAGMA using the given boolean value, if using
72
- # SQLite 3.6.19+. If not using 3.6.19+, no error is raised. See pragma_set.
73
- # Consider using the :foreign_keys Database option instead.
74
- def foreign_keys=(value)
75
- pragma_set(:foreign_keys, !!value ? 'on' : 'off') if sqlite_version >= 30619
62
+ # Set the integer_booleans option using the passed in :integer_boolean option.
63
+ def set_integer_booleans
64
+ @integer_booleans = @opts.has_key?(:integer_booleans) ? typecast_value_boolean(@opts[:integer_booleans]) : true
76
65
  end
77
66
 
78
67
  # Return the array of foreign key info hashes using the foreign_key_list PRAGMA,
@@ -80,7 +69,7 @@ module Sequel
80
69
  def foreign_key_list(table, opts=OPTS)
81
70
  m = output_identifier_meth
82
71
  h = {}
83
- metadata_dataset.with_sql("PRAGMA foreign_key_list(?)", input_identifier_meth.call(table)).each do |row|
72
+ _foreign_key_list_ds(table).each do |row|
84
73
  if r = h[row[:id]]
85
74
  r[:columns] << m.call(row[:from])
86
75
  r[:key] << m.call(row[:to]) if r[:key]
@@ -91,14 +80,31 @@ module Sequel
91
80
  h.values
92
81
  end
93
82
 
83
+ def freeze
84
+ sqlite_version
85
+ use_timestamp_timezones?
86
+ super
87
+ end
88
+
94
89
  # Use the index_list and index_info PRAGMAs to determine the indexes on the table.
95
90
  def indexes(table, opts=OPTS)
96
91
  m = output_identifier_meth
97
92
  im = input_identifier_meth
98
93
  indexes = {}
94
+ table = table.value if table.is_a?(Sequel::SQL::Identifier)
99
95
  metadata_dataset.with_sql("PRAGMA index_list(?)", im.call(table)).each do |r|
100
- # :only_autocreated internal option can be used to get only autocreated indexes
101
- next if (!!(r[:name] =~ PRIMARY_KEY_INDEX_RE) ^ !!opts[:only_autocreated])
96
+ if opts[:only_autocreated]
97
+ # If specifically asked for only autocreated indexes, then return those an only those
98
+ next unless r[:name] =~ /\Asqlite_autoindex_/
99
+ elsif r.has_key?(:origin)
100
+ # If origin is set, then only exclude primary key indexes and partial indexes
101
+ next if r[:origin] == 'pk'
102
+ next if r[:partial].to_i == 1
103
+ else
104
+ # When :origin key not present, assume any autoindex could be a primary key one and exclude it
105
+ next if r[:name] =~ /\Asqlite_autoindex_/
106
+ end
107
+
102
108
  indexes[m.call(r[:name])] = {:unique=>r[:unique].to_i==1}
103
109
  end
104
110
  indexes.each do |k, v|
@@ -107,26 +113,6 @@ module Sequel
107
113
  indexes
108
114
  end
109
115
 
110
- # Get the value of the given PRAGMA.
111
- def pragma_get(name)
112
- self["PRAGMA #{name}"].single_value
113
- end
114
-
115
- # Set the value of the given PRAGMA to value.
116
- #
117
- # This method is not thread safe, and will not work correctly if there
118
- # are multiple connections in the Database's connection pool. PRAGMA
119
- # modifications should be done when the connection is created, using
120
- # an option provided when creating the Database object.
121
- def pragma_set(name, value)
122
- execute_ddl("PRAGMA #{name} = #{value}")
123
- end
124
-
125
- # Set the integer_booleans option using the passed in :integer_boolean option.
126
- def set_integer_booleans
127
- @integer_booleans = @opts.has_key?(:integer_booleans) ? typecast_value_boolean(@opts[:integer_booleans]) : true
128
- end
129
-
130
116
  # The version of the server as an integer, where 3.6.19 = 30619.
131
117
  # If the server version can't be determined, 0 is used.
132
118
  def sqlite_version
@@ -170,55 +156,57 @@ module Sequel
170
156
  defined?(@use_timestamp_timezones) ? @use_timestamp_timezones : (@use_timestamp_timezones = false)
171
157
  end
172
158
 
173
- # A symbol signifying the value of the synchronous PRAGMA.
174
- def synchronous
175
- SYNCHRONOUS[pragma_get(:synchronous).to_i]
176
- end
177
-
178
- # Set the synchronous PRAGMA using the given symbol (:off, :normal, or :full). See pragma_set.
179
- # Consider using the :synchronous Database option instead.
180
- def synchronous=(value)
181
- value = SYNCHRONOUS.index(value) || (raise Error, "Invalid value for synchronous option. Please specify one of :off, :normal, :full.")
182
- pragma_set(:synchronous, value)
183
- end
184
-
185
159
  # Array of symbols specifying the table names in the current database.
186
160
  #
187
161
  # Options:
188
162
  # :server :: Set the server to use.
189
163
  def tables(opts=OPTS)
190
- tables_and_views(TABLES_FILTER, opts)
191
- end
192
-
193
- # A symbol signifying the value of the temp_store PRAGMA.
194
- def temp_store
195
- TEMP_STORE[pragma_get(:temp_store).to_i]
164
+ tables_and_views(Sequel.~(:name=>'sqlite_sequence') & {:type => 'table'}, opts)
196
165
  end
197
166
 
198
- # Set the temp_store PRAGMA using the given symbol (:default, :file, or :memory). See pragma_set.
199
- # Consider using the :temp_store Database option instead.
200
- def temp_store=(value)
201
- value = TEMP_STORE.index(value) || (raise Error, "Invalid value for temp_store option. Please specify one of :default, :file, :memory.")
202
- pragma_set(:temp_store, value)
167
+ # Creates a dataset that uses the VALUES clause:
168
+ #
169
+ # DB.values([[1, 2], [3, 4]])
170
+ # # VALUES ((1, 2), (3, 4))
171
+ def values(v)
172
+ @default_dataset.clone(:values=>v)
203
173
  end
204
-
174
+
205
175
  # Array of symbols specifying the view names in the current database.
206
176
  #
207
177
  # Options:
208
178
  # :server :: Set the server to use.
209
179
  def views(opts=OPTS)
210
- tables_and_views(VIEWS_FILTER, opts)
180
+ tables_and_views({:type => 'view'}, opts)
211
181
  end
212
182
 
213
183
  private
214
184
 
185
+ # Dataset used for parsing foreign key lists
186
+ def _foreign_key_list_ds(table)
187
+ metadata_dataset.with_sql("PRAGMA foreign_key_list(?)", input_identifier_meth.call(table))
188
+ end
189
+
190
+ # Dataset used for parsing schema
191
+ def _parse_pragma_ds(table_name, opts)
192
+ metadata_dataset.with_sql("PRAGMA table_#{'x' if sqlite_version > 33100}info(?)", input_identifier_meth(opts[:dataset]).call(table_name))
193
+ end
194
+
215
195
  # Run all alter_table commands in a transaction. This is technically only
216
196
  # needed for drop column.
217
197
  def apply_alter_table(table, ops)
218
- fks = foreign_keys
219
- self.foreign_keys = false if fks
198
+ fks = fetch("PRAGMA foreign_keys")
199
+ if fks
200
+ run "PRAGMA foreign_keys = 0"
201
+ run "PRAGMA legacy_alter_table = 1" if sqlite_version >= 32600
202
+ end
220
203
  transaction do
221
- if ops.length > 1 && ops.all?{|op| op[:op] == :add_constraint}
204
+ if ops.length > 1 && ops.all?{|op| op[:op] == :add_constraint || op[:op] == :set_column_null}
205
+ null_ops, ops = ops.partition{|op| op[:op] == :set_column_null}
206
+
207
+ # Apply NULL/NOT NULL ops first, since those should be purely idependent of the constraints.
208
+ null_ops.each{|op| alter_table_sql_list(table, [op]).flatten.each{|sql| execute_ddl(sql)}}
209
+
222
210
  # If you are just doing constraints, apply all of them at the same time,
223
211
  # as otherwise all but the last one get lost.
224
212
  alter_table_sql_list(table, [{:op=>:add_constraints, :ops=>ops}]).flatten.each{|sql| execute_ddl(sql)}
@@ -228,8 +216,12 @@ module Sequel
228
216
  ops.each{|op| alter_table_sql_list(table, [op]).flatten.each{|sql| execute_ddl(sql)}}
229
217
  end
230
218
  end
219
+ remove_cached_schema(table)
231
220
  ensure
232
- self.foreign_keys = true if fks
221
+ if fks
222
+ run "PRAGMA foreign_keys = 1"
223
+ run "PRAGMA legacy_alter_table = 0" if sqlite_version >= 32600
224
+ end
233
225
  end
234
226
 
235
227
  # SQLite supports limited table modification. You can add a column
@@ -250,8 +242,12 @@ module Sequel
250
242
  ocp = lambda{|oc| oc.delete_if{|c| c.to_s == op[:name].to_s}}
251
243
  duplicate_table(table, :old_columns_proc=>ocp){|columns| columns.delete_if{|s| s[:name].to_s == op[:name].to_s}}
252
244
  when :rename_column
253
- ncp = lambda{|nc| nc.map!{|c| c.to_s == op[:name].to_s ? op[:new_name] : c}}
254
- duplicate_table(table, :new_columns_proc=>ncp){|columns| columns.each{|s| s[:name] = op[:new_name] if s[:name].to_s == op[:name].to_s}}
245
+ if sqlite_version >= 32500
246
+ super
247
+ else
248
+ ncp = lambda{|nc| nc.map!{|c| c.to_s == op[:name].to_s ? op[:new_name] : c}}
249
+ duplicate_table(table, :new_columns_proc=>ncp){|columns| columns.each{|s| s[:name] = op[:new_name] if s[:name].to_s == op[:name].to_s}}
250
+ end
255
251
  when :set_column_default
256
252
  duplicate_table(table){|columns| columns.each{|s| s[:default] = op[:default] if s[:name].to_s == op[:name].to_s}}
257
253
  when :set_column_null
@@ -261,13 +257,20 @@ module Sequel
261
257
  when :drop_constraint
262
258
  case op[:type]
263
259
  when :primary_key
264
- duplicate_table(table){|columns| columns.each{|s| s[:primary_key] = nil}}
260
+ duplicate_table(table) do |columns|
261
+ columns.each do |s|
262
+ s[:unique] = false if s[:primary_key]
263
+ s[:primary_key] = s[:auto_increment] = nil
264
+ end
265
+ end
265
266
  when :foreign_key
266
267
  if op[:columns]
267
268
  duplicate_table(table, :skip_foreign_key_columns=>op[:columns])
268
269
  else
269
270
  duplicate_table(table, :no_foreign_keys=>true)
270
271
  end
272
+ when :unique
273
+ duplicate_table(table, :no_unique=>true)
271
274
  else
272
275
  duplicate_table(table)
273
276
  end
@@ -296,15 +299,21 @@ module Sequel
296
299
  end
297
300
  end
298
301
 
299
- # Surround default with parens to appease SQLite
302
+ # SQLite allows adding primary key constraints on NULLABLE columns, but then
303
+ # does not enforce NOT NULL for such columns, so force setting the columns NOT NULL.
304
+ def can_add_primary_key_constraint_on_nullable_columns?
305
+ false
306
+ end
307
+
308
+ # Surround default with parens to appease SQLite. Add support for GENERATED ALWAYS AS.
300
309
  def column_definition_default_sql(sql, column)
301
310
  sql << " DEFAULT (#{literal(column[:default])})" if column.include?(:default)
302
- end
303
-
304
- # Add null/not null SQL fragment to column creation SQL.
305
- def column_definition_null_sql(sql, column)
306
- column = column.merge(:null=>false) if column[:primary_key]
307
- super(sql, column)
311
+ if (generated = column[:generated_always_as])
312
+ if (generated_type = column[:generated_type]) && (generated_type == :stored || generated_type == :virtual)
313
+ generated_type = generated_type.to_s.upcase
314
+ end
315
+ sql << " GENERATED ALWAYS AS (#{literal(generated)}) #{generated_type}"
316
+ end
308
317
  end
309
318
 
310
319
  # Array of PRAGMA SQL statements based on the Database options that should be applied to
@@ -326,13 +335,13 @@ module Sequel
326
335
 
327
336
  # SQLite support creating temporary views.
328
337
  def create_view_prefix_sql(name, options)
329
- "CREATE #{'TEMPORARY 'if options[:temp]}VIEW #{quote_schema_table(name)}"
338
+ create_view_sql_append_columns("CREATE #{'TEMPORARY 'if options[:temp]}VIEW #{quote_schema_table(name)}", options[:columns])
330
339
  end
331
340
 
332
341
  DATABASE_ERROR_REGEXPS = {
333
342
  /(is|are) not unique\z|PRIMARY KEY must be unique\z|UNIQUE constraint failed: .+\z/ => UniqueConstraintViolation,
334
343
  /foreign key constraint failed\z/i => ForeignKeyConstraintViolation,
335
- /\ACHECK constraint failed/ => CheckConstraintViolation,
344
+ /\A(SQLITE ERROR 275 \(CONSTRAINT_CHECK\) : )?CHECK constraint failed/ => CheckConstraintViolation,
336
345
  /\A(SQLITE ERROR 19 \(CONSTRAINT\) : )?constraint failed\z/ => ConstraintViolation,
337
346
  /may not be NULL\z|NOT NULL constraint failed: .+\z/ => NotNullConstraintViolation,
338
347
  /\ASQLITE ERROR \d+ \(\) : CHECK constraint failed: / => CheckConstraintViolation
@@ -341,13 +350,32 @@ module Sequel
341
350
  DATABASE_ERROR_REGEXPS
342
351
  end
343
352
 
353
+ # Recognize SQLite error codes if the exception provides access to them.
354
+ def database_specific_error_class(exception, opts)
355
+ case sqlite_error_code(exception)
356
+ when 1299
357
+ NotNullConstraintViolation
358
+ when 1555, 2067, 2579
359
+ UniqueConstraintViolation
360
+ when 787
361
+ ForeignKeyConstraintViolation
362
+ when 275
363
+ CheckConstraintViolation
364
+ when 19
365
+ ConstraintViolation
366
+ when 517
367
+ SerializationFailure
368
+ else
369
+ super
370
+ end
371
+ end
372
+
344
373
  # The array of column schema hashes for the current columns in the table
345
374
  def defined_columns_for(table)
346
- cols = parse_pragma(table, {})
375
+ cols = parse_pragma(table, OPTS)
347
376
  cols.each do |c|
348
377
  c[:default] = LiteralString.new(c[:default]) if c[:default]
349
378
  c[:type] = c[:db_type]
350
- c.delete(:auto_increment)
351
379
  end
352
380
  cols
353
381
  end
@@ -393,14 +421,22 @@ module Sequel
393
421
 
394
422
  # Determine unique constraints and make sure the new columns have them
395
423
  unique_columns = []
396
- indexes(table, :only_autocreated=>true).each_value do |h|
397
- unique_columns.concat(h[:columns]) if h[:columns].length == 1 && h[:unique]
424
+ skip_indexes = []
425
+ indexes(table, :only_autocreated=>true).each do |name, h|
426
+ skip_indexes << name
427
+ if h[:unique]
428
+ if h[:columns].length == 1
429
+ unique_columns.concat(h[:columns])
430
+ elsif h[:columns].map(&:to_s) != pks && !opts[:no_unique]
431
+ constraints << {:type=>:unique, :columns=>h[:columns]}
432
+ end
433
+ end
398
434
  end
399
435
  unique_columns -= pks
400
436
  unless unique_columns.empty?
401
437
  unique_columns.map!{|c| quote_identifier(c)}
402
438
  def_columns.each do |c|
403
- c[:unique] = true if unique_columns.include?(quote_identifier(c[:name]))
439
+ c[:unique] = true if unique_columns.include?(quote_identifier(c[:name])) && c[:unique] != false
404
440
  end
405
441
  end
406
442
 
@@ -417,6 +453,7 @@ module Sequel
417
453
  "DROP TABLE #{bt}"
418
454
  ]
419
455
  indexes(table).each do |name, h|
456
+ next if skip_indexes.include?(name)
420
457
  if (h[:columns].map(&:to_s) - new_columns).empty?
421
458
  a << alter_table_sql(table, h.merge(:op=>:add_index, :name=>name))
422
459
  end
@@ -424,19 +461,9 @@ module Sequel
424
461
  a
425
462
  end
426
463
 
427
- # SQLite folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on input.
428
- def identifier_input_method_default
429
- nil
430
- end
431
-
432
- # SQLite folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on output.
433
- def identifier_output_method_default
434
- nil
435
- end
436
-
437
464
  # Does the reverse of on_delete_clause, eg. converts strings like +'SET NULL'+
438
465
  # to symbols +:set_null+.
439
- def on_delete_sql_to_sym str
466
+ def on_delete_sql_to_sym(str)
440
467
  case str
441
468
  when 'RESTRICT'
442
469
  :restrict
@@ -453,18 +480,43 @@ module Sequel
453
480
 
454
481
  # Parse the output of the table_info pragma
455
482
  def parse_pragma(table_name, opts)
456
- metadata_dataset.with_sql("PRAGMA table_info(?)", input_identifier_meth(opts[:dataset]).call(table_name)).map do |row|
483
+ pks = 0
484
+ sch = _parse_pragma_ds(table_name, opts).map do |row|
485
+ if sqlite_version > 33100
486
+ # table_xinfo PRAGMA used, remove hidden columns
487
+ # that are not generated columns
488
+ if row[:generated] = (row.delete(:hidden) != 0)
489
+ next unless row[:type].end_with?(' GENERATED ALWAYS')
490
+ row[:type] = row[:type].sub(' GENERATED ALWAYS', '')
491
+ end
492
+ end
493
+
457
494
  row.delete(:cid)
458
495
  row[:allow_null] = row.delete(:notnull).to_i == 0
459
496
  row[:default] = row.delete(:dflt_value)
460
497
  row[:default] = nil if blank_object?(row[:default]) || row[:default] == 'NULL'
461
498
  row[:db_type] = row.delete(:type)
462
499
  if row[:primary_key] = row.delete(:pk).to_i > 0
500
+ pks += 1
501
+ # Guess that an integer primary key uses auto increment,
502
+ # since that is Sequel's default and SQLite does not provide
503
+ # a way to introspect whether it is actually autoincrementing.
463
504
  row[:auto_increment] = row[:db_type].downcase == 'integer'
464
505
  end
465
506
  row[:type] = schema_column_type(row[:db_type])
466
507
  row
467
508
  end
509
+
510
+ sch.compact!
511
+
512
+ if pks > 1
513
+ # SQLite does not allow use of auto increment for tables
514
+ # with composite primary keys, so remove auto_increment
515
+ # if composite primary keys are detected.
516
+ sch.each{|r| r.delete(:auto_increment)}
517
+ end
518
+
519
+ sch
468
520
  end
469
521
 
470
522
  # SQLite supports schema parsing using the table_info PRAGMA, so
@@ -476,78 +528,95 @@ module Sequel
476
528
  end
477
529
  end
478
530
 
531
+ # Don't support SQLite error codes for exceptions by default.
532
+ def sqlite_error_code(exception)
533
+ nil
534
+ end
535
+
479
536
  # Backbone of the tables and views support.
480
537
  def tables_and_views(filter, opts)
481
538
  m = output_identifier_meth
482
- metadata_dataset.from(:sqlite_master).server(opts[:server]).filter(filter).map{|r| m.call(r[:name])}
539
+ metadata_dataset.from(:sqlite_master).server(opts[:server]).where(filter).map{|r| m.call(r[:name])}
483
540
  end
484
541
 
485
542
  # SQLite only supports AUTOINCREMENT on integer columns, not
486
543
  # bigint columns, so use integer instead of bigint for those
487
544
  # columns.
488
- def type_literal_generic_bignum(column)
545
+ def type_literal_generic_bignum_symbol(column)
489
546
  column[:auto_increment] ? :integer : super
490
547
  end
491
548
  end
492
549
 
493
- # Instance methods for datasets that connect to an SQLite database
494
550
  module DatasetMethods
495
551
  include Dataset::Replace
552
+ include UnmodifiedIdentifiers::DatasetMethods
553
+
554
+ # The allowed values for insert_conflict
555
+ INSERT_CONFLICT_RESOLUTIONS = %w'ROLLBACK ABORT FAIL IGNORE REPLACE'.each(&:freeze).freeze
496
556
 
497
- CONSTANT_MAP = {:CURRENT_DATE=>"date(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIMESTAMP=>"datetime(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIME=>"time(CURRENT_TIMESTAMP, 'localtime')".freeze}
498
- EMULATED_FUNCTION_MAP = {:char_length=>'length'.freeze}
499
- EXTRACT_MAP = {:year=>"'%Y'", :month=>"'%m'", :day=>"'%d'", :hour=>"'%H'", :minute=>"'%M'", :second=>"'%f'"}
500
- NOT_SPACE = Dataset::NOT_SPACE
501
- COMMA = Dataset::COMMA
502
- PAREN_CLOSE = Dataset::PAREN_CLOSE
503
- AS = Dataset::AS
504
- APOS = Dataset::APOS
505
- EXTRACT_OPEN = "CAST(strftime(".freeze
506
- EXTRACT_CLOSE = ') AS '.freeze
507
- NUMERIC = 'NUMERIC'.freeze
508
- INTEGER = 'INTEGER'.freeze
509
- BACKTICK = '`'.freeze
510
- BACKTICK_RE = /`/.freeze
511
- DOUBLE_BACKTICK = '``'.freeze
512
- BLOB_START = "X'".freeze
513
- HSTAR = "H*".freeze
514
- DATE_OPEN = "date(".freeze
515
- DATETIME_OPEN = "datetime(".freeze
516
- ONLY_OFFSET = " LIMIT -1 OFFSET ".freeze
557
+ CONSTANT_MAP = {:CURRENT_DATE=>"date(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIMESTAMP=>"datetime(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIME=>"time(CURRENT_TIMESTAMP, 'localtime')".freeze}.freeze
558
+ EXTRACT_MAP = {:year=>"'%Y'", :month=>"'%m'", :day=>"'%d'", :hour=>"'%H'", :minute=>"'%M'", :second=>"'%f'"}.freeze
559
+ EXTRACT_MAP.each_value(&:freeze)
517
560
 
518
561
  Dataset.def_sql_method(self, :delete, [['if db.sqlite_version >= 30803', %w'with delete from where'], ["else", %w'delete from where']])
519
- Dataset.def_sql_method(self, :insert, [['if db.sqlite_version >= 30803', %w'with insert into columns values'], ["else", %w'insert into columns values']])
562
+ Dataset.def_sql_method(self, :insert, [['if db.sqlite_version >= 30803', %w'with insert conflict into columns values on_conflict'], ["else", %w'insert conflict into columns values']])
563
+ Dataset.def_sql_method(self, :select, [['if opts[:values]', %w'with values compounds'], ['else', %w'with select distinct columns from join where group having window compounds order limit lock']])
520
564
  Dataset.def_sql_method(self, :update, [['if db.sqlite_version >= 30803', %w'with update table set where'], ["else", %w'update table set where']])
521
565
 
522
566
  def cast_sql_append(sql, expr, type)
523
567
  if type == Time or type == DateTime
524
- sql << DATETIME_OPEN
568
+ sql << "datetime("
525
569
  literal_append(sql, expr)
526
- sql << PAREN_CLOSE
570
+ sql << ')'
527
571
  elsif type == Date
528
- sql << DATE_OPEN
572
+ sql << "date("
529
573
  literal_append(sql, expr)
530
- sql << PAREN_CLOSE
574
+ sql << ')'
531
575
  else
532
576
  super
533
577
  end
534
578
  end
535
579
 
536
580
  # SQLite doesn't support a NOT LIKE b, you need to use NOT (a LIKE b).
537
- # It doesn't support xor or the extract function natively, so those have to be emulated.
581
+ # It doesn't support xor, power, or the extract function natively, so those have to be emulated.
538
582
  def complex_expression_sql_append(sql, op, args)
539
583
  case op
540
584
  when :"NOT LIKE", :"NOT ILIKE"
541
- sql << NOT_SPACE
585
+ sql << 'NOT '
542
586
  complex_expression_sql_append(sql, (op == :"NOT ILIKE" ? :ILIKE : :LIKE), args)
543
587
  when :^
544
588
  complex_expression_arg_pairs_append(sql, args){|a, b| Sequel.lit(["((~(", " & ", ")) & (", " | ", "))"], a, b, a, b)}
589
+ when :**
590
+ unless (exp = args[1]).is_a?(Integer)
591
+ raise(Sequel::Error, "can only emulate exponentiation on SQLite if exponent is an integer, given #{exp.inspect}")
592
+ end
593
+ case exp
594
+ when 0
595
+ sql << '1'
596
+ else
597
+ sql << '('
598
+ arg = args[0]
599
+ if exp < 0
600
+ invert = true
601
+ exp = exp.abs
602
+ sql << '(1.0 / ('
603
+ end
604
+ (exp - 1).times do
605
+ literal_append(sql, arg)
606
+ sql << " * "
607
+ end
608
+ literal_append(sql, arg)
609
+ sql << ')'
610
+ if invert
611
+ sql << "))"
612
+ end
613
+ end
545
614
  when :extract
546
- part = args.at(0)
615
+ part = args[0]
547
616
  raise(Sequel::Error, "unsupported extract argument: #{part.inspect}") unless format = EXTRACT_MAP[part]
548
- sql << EXTRACT_OPEN << format << COMMA
549
- literal_append(sql, args.at(1))
550
- sql << EXTRACT_CLOSE << (part == :second ? NUMERIC : INTEGER) << PAREN_CLOSE
617
+ sql << "CAST(strftime(" << format << ', '
618
+ literal_append(sql, args[1])
619
+ sql << ') AS ' << (part == :second ? 'NUMERIC' : 'INTEGER') << ')'
551
620
  else
552
621
  super
553
622
  end
@@ -556,7 +625,7 @@ module Sequel
556
625
  # SQLite has CURRENT_TIMESTAMP and related constants in UTC instead
557
626
  # of in localtime, so convert those constants to local time.
558
627
  def constant_sql_append(sql, constant)
559
- if c = CONSTANT_MAP[constant]
628
+ if (c = CONSTANT_MAP[constant]) && !db.current_timestamp_utc
560
629
  sql << c
561
630
  else
562
631
  super
@@ -571,7 +640,7 @@ module Sequel
571
640
  end
572
641
 
573
642
  # Return an array of strings specifying a query explanation for a SELECT of the
574
- # current dataset. Currently, the options are ignore, but it accepts options
643
+ # current dataset. Currently, the options are ignored, but it accepts options
575
644
  # to be compatible with other adapters.
576
645
  def explain(opts=nil)
577
646
  # Load the PrettyTable class, needed for explain output
@@ -590,7 +659,7 @@ module Sequel
590
659
 
591
660
  # SQLite uses the nonstandard ` (backtick) for quoting identifiers.
592
661
  def quoted_identifier_append(sql, c)
593
- sql << BACKTICK << c.to_s.gsub(BACKTICK_RE, DOUBLE_BACKTICK) << BACKTICK
662
+ sql << '`' << c.to_s.gsub('`', '``') << '`'
594
663
  end
595
664
 
596
665
  # When a qualified column is selected on SQLite and the qualifier
@@ -604,12 +673,81 @@ module Sequel
604
673
  super
605
674
  end
606
675
  end
607
-
676
+
677
+ # Handle uniqueness violations when inserting, by using a specified
678
+ # resolution algorithm. With no options, uses INSERT OR REPLACE. SQLite
679
+ # supports the following conflict resolution algoriths: ROLLBACK, ABORT,
680
+ # FAIL, IGNORE and REPLACE.
681
+ #
682
+ # On SQLite 3.24.0+, you can pass a hash to use an ON CONFLICT clause.
683
+ # With out :update option, uses ON CONFLICT DO NOTHING. Options:
684
+ #
685
+ # :conflict_where :: The index filter, when using a partial index to determine uniqueness.
686
+ # :target :: The column name or expression to handle uniqueness violations on.
687
+ # :update :: A hash of columns and values to set. Uses ON CONFLICT DO UPDATE.
688
+ # :update_where :: A WHERE condition to use for the update.
689
+ #
690
+ # Examples:
691
+ #
692
+ # DB[:table].insert_conflict.insert(a: 1, b: 2)
693
+ # # INSERT OR IGNORE INTO TABLE (a, b) VALUES (1, 2)
694
+ #
695
+ # DB[:table].insert_conflict(:replace).insert(a: 1, b: 2)
696
+ # # INSERT OR REPLACE INTO TABLE (a, b) VALUES (1, 2)
697
+ #
698
+ # DB[:table].insert_conflict({}).insert(a: 1, b: 2)
699
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
700
+ # # ON CONFLICT DO NOTHING
701
+ #
702
+ # DB[:table].insert_conflict(target: :a).insert(a: 1, b: 2)
703
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
704
+ # # ON CONFLICT (a) DO NOTHING
705
+ #
706
+ # DB[:table].insert_conflict(target: :a, conflict_where: {c: true}).insert(a: 1, b: 2)
707
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
708
+ # # ON CONFLICT (a) WHERE (c IS TRUE) DO NOTHING
709
+ #
710
+ # DB[:table].insert_conflict(target: :a, update: {b: Sequel[:excluded][:b]}).insert(a: 1, b: 2)
711
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
712
+ # # ON CONFLICT (a) DO UPDATE SET b = excluded.b
713
+ #
714
+ # DB[:table].insert_conflict(target: :a,
715
+ # update: {b: Sequel[:excluded][:b]}, update_where: {Sequel[:table][:status_id] => 1}).insert(a: 1, b: 2)
716
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
717
+ # # ON CONFLICT (a) DO UPDATE SET b = excluded.b WHERE (table.status_id = 1)
718
+ def insert_conflict(opts = :ignore)
719
+ case opts
720
+ when Symbol, String
721
+ unless INSERT_CONFLICT_RESOLUTIONS.include?(opts.to_s.upcase)
722
+ raise Error, "Invalid symbol or string passed to Dataset#insert_conflict: #{opts.inspect}. The allowed values are: :rollback, :abort, :fail, :ignore, or :replace"
723
+ end
724
+ clone(:insert_conflict => opts)
725
+ when Hash
726
+ clone(:insert_on_conflict => opts)
727
+ else
728
+ raise Error, "Invalid value passed to Dataset#insert_conflict: #{opts.inspect}, should use a symbol or a hash"
729
+ end
730
+ end
731
+
732
+ # Ignore uniqueness/exclusion violations when inserting, using INSERT OR IGNORE.
733
+ # Exists mostly for compatibility to MySQL's insert_ignore. Example:
734
+ #
735
+ # DB[:table].insert_ignore.insert(a: 1, b: 2)
736
+ # # INSERT OR IGNORE INTO TABLE (a, b) VALUES (1, 2)
737
+ def insert_ignore
738
+ insert_conflict(:ignore)
739
+ end
740
+
608
741
  # SQLite 3.8.3+ supports common table expressions.
609
742
  def supports_cte?(type=:select)
610
743
  db.sqlite_version >= 30803
611
744
  end
612
745
 
746
+ # SQLite supports CTEs in subqueries if it supports CTEs.
747
+ def supports_cte_in_subqueries?
748
+ supports_cte?
749
+ end
750
+
613
751
  # SQLite does not support table aliases with column aliases
614
752
  def supports_derived_column_lists?
615
753
  false
@@ -641,14 +779,32 @@ module Sequel
641
779
  def supports_where_true?
642
780
  false
643
781
  end
782
+
783
+ # SQLite 3.28+ supports the WINDOW clause.
784
+ def supports_window_clause?
785
+ db.sqlite_version >= 32800
786
+ end
644
787
 
788
+ # SQLite 3.25+ supports window functions. However, support is only enabled
789
+ # on SQLite 3.26.0+ because internal Sequel usage of window functions
790
+ # to implement eager loading of limited associations triggers
791
+ # an SQLite crash bug in versions 3.25.0-3.25.3.
792
+ def supports_window_functions?
793
+ db.sqlite_version >= 32600
794
+ end
795
+
796
+ # SQLite 3.28.0+ supports all window frame options that Sequel supports
797
+ def supports_window_function_frame_option?(option)
798
+ db.sqlite_version >= 32800 ? true : super
799
+ end
800
+
645
801
  private
646
802
 
647
803
  # SQLite uses string literals instead of identifiers in AS clauses.
648
804
  def as_sql_append(sql, aliaz, column_aliases=nil)
649
805
  raise Error, "sqlite does not support derived column lists" if column_aliases
650
806
  aliaz = aliaz.value if aliaz.is_a?(SQL::Identifier)
651
- sql << AS
807
+ sql << ' AS '
652
808
  literal_append(sql, aliaz.to_s)
653
809
  end
654
810
 
@@ -676,12 +832,49 @@ module Sequel
676
832
 
677
833
  # SQL fragment specifying a list of identifiers
678
834
  def identifier_list(columns)
679
- columns.map{|i| quote_identifier(i)}.join(COMMA)
835
+ columns.map{|i| quote_identifier(i)}.join(', ')
680
836
  end
681
837
 
838
+ # Add OR clauses to SQLite INSERT statements
839
+ def insert_conflict_sql(sql)
840
+ if resolution = @opts[:insert_conflict]
841
+ sql << " OR " << resolution.to_s.upcase
842
+ end
843
+ end
844
+
845
+ # Add ON CONFLICT clause if it should be used
846
+ def insert_on_conflict_sql(sql)
847
+ if opts = @opts[:insert_on_conflict]
848
+ sql << " ON CONFLICT"
849
+
850
+ if target = opts[:constraint]
851
+ sql << " ON CONSTRAINT "
852
+ identifier_append(sql, target)
853
+ elsif target = opts[:target]
854
+ sql << ' '
855
+ identifier_append(sql, Array(target))
856
+ if conflict_where = opts[:conflict_where]
857
+ sql << " WHERE "
858
+ literal_append(sql, conflict_where)
859
+ end
860
+ end
861
+
862
+ if values = opts[:update]
863
+ sql << " DO UPDATE SET "
864
+ update_sql_values_hash(sql, values)
865
+ if update_where = opts[:update_where]
866
+ sql << " WHERE "
867
+ literal_append(sql, update_where)
868
+ end
869
+ else
870
+ sql << " DO NOTHING"
871
+ end
872
+ end
873
+ end
874
+
682
875
  # SQLite uses a preceding X for hex escaping strings
683
876
  def literal_blob_append(sql, v)
684
- sql << BLOB_START << v.unpack(HSTAR).first << APOS
877
+ sql << "X'" << v.unpack("H*").first << "'"
685
878
  end
686
879
 
687
880
  # Respect the database integer_booleans setting, using 0 or 'f'.
@@ -700,6 +893,20 @@ module Sequel
700
893
  db.sqlite_version >= 30711 ? :values : :union
701
894
  end
702
895
 
896
+ # Emulate the char_length function with length
897
+ def native_function_name(emulated_function)
898
+ if emulated_function == :char_length
899
+ 'length'
900
+ else
901
+ super
902
+ end
903
+ end
904
+
905
+ # SQLite supports NULLS FIRST/LAST natively in 3.30+.
906
+ def requires_emulating_nulls_first?
907
+ db.sqlite_version < 33000
908
+ end
909
+
703
910
  # SQLite does not support FOR UPDATE, but silently ignore it
704
911
  # instead of raising an error for compatibility with other
705
912
  # databases.
@@ -708,10 +915,26 @@ module Sequel
708
915
  end
709
916
 
710
917
  def select_only_offset_sql(sql)
711
- sql << ONLY_OFFSET
918
+ sql << " LIMIT -1 OFFSET "
712
919
  literal_append(sql, @opts[:offset])
713
920
  end
714
921
 
922
+ # Support VALUES clause instead of the SELECT clause to return rows.
923
+ def select_values_sql(sql)
924
+ sql << "VALUES "
925
+ expression_list_append(sql, opts[:values])
926
+ end
927
+
928
+ # SQLite does not support CTEs directly inside UNION/INTERSECT/EXCEPT.
929
+ def supports_cte_in_compounds?
930
+ false
931
+ end
932
+
933
+ # SQLite 3.30 supports the FILTER clause for aggregate functions.
934
+ def supports_filtered_aggregates?
935
+ db.sqlite_version >= 33000
936
+ end
937
+
715
938
  # SQLite supports quoted function names.
716
939
  def supports_quoted_function_names?
717
940
  true