sequel 3.21.0 → 3.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. data/CHANGELOG +855 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +23 -7
  4. data/Rakefile +42 -24
  5. data/bin/sequel +26 -8
  6. data/doc/active_record.rdoc +1 -0
  7. data/doc/advanced_associations.rdoc +171 -11
  8. data/doc/association_basics.rdoc +293 -43
  9. data/doc/dataset_basics.rdoc +5 -5
  10. data/doc/dataset_filtering.rdoc +8 -0
  11. data/doc/mass_assignment.rdoc +56 -0
  12. data/doc/migration.rdoc +85 -552
  13. data/doc/model_hooks.rdoc +78 -27
  14. data/doc/object_model.rdoc +541 -0
  15. data/doc/opening_databases.rdoc +97 -50
  16. data/doc/prepared_statements.rdoc +40 -14
  17. data/doc/querying.rdoc +28 -4
  18. data/doc/reflection.rdoc +30 -4
  19. data/doc/release_notes/3.22.0.txt +39 -0
  20. data/doc/release_notes/3.23.0.txt +172 -0
  21. data/doc/release_notes/3.24.0.txt +420 -0
  22. data/doc/release_notes/3.25.0.txt +88 -0
  23. data/doc/release_notes/3.26.0.txt +88 -0
  24. data/doc/release_notes/3.27.0.txt +82 -0
  25. data/doc/release_notes/3.28.0.txt +304 -0
  26. data/doc/release_notes/3.29.0.txt +459 -0
  27. data/doc/release_notes/3.30.0.txt +135 -0
  28. data/doc/release_notes/3.31.0.txt +146 -0
  29. data/doc/release_notes/3.32.0.txt +202 -0
  30. data/doc/release_notes/3.33.0.txt +157 -0
  31. data/doc/release_notes/3.34.0.txt +671 -0
  32. data/doc/release_notes/3.35.0.txt +144 -0
  33. data/doc/release_notes/3.36.0.txt +245 -0
  34. data/doc/schema_modification.rdoc +572 -0
  35. data/doc/sharding.rdoc +95 -3
  36. data/doc/testing.rdoc +129 -0
  37. data/doc/thread_safety.rdoc +17 -0
  38. data/doc/transactions.rdoc +137 -0
  39. data/doc/virtual_rows.rdoc +51 -2
  40. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  41. data/lib/sequel/adapters/ado.rb +40 -18
  42. data/lib/sequel/adapters/amalgalite.rb +17 -9
  43. data/lib/sequel/adapters/db2.rb +175 -86
  44. data/lib/sequel/adapters/dbi.rb +15 -15
  45. data/lib/sequel/adapters/do/mysql.rb +17 -11
  46. data/lib/sequel/adapters/do/postgres.rb +1 -57
  47. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  48. data/lib/sequel/adapters/do.rb +18 -36
  49. data/lib/sequel/adapters/firebird.rb +27 -208
  50. data/lib/sequel/adapters/ibmdb.rb +453 -0
  51. data/lib/sequel/adapters/informix.rb +6 -23
  52. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  53. data/lib/sequel/adapters/jdbc/db2.rb +47 -0
  54. data/lib/sequel/adapters/jdbc/derby.rb +287 -0
  55. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  56. data/lib/sequel/adapters/jdbc/h2.rb +73 -31
  57. data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
  58. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  59. data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
  60. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  61. data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
  62. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  63. data/lib/sequel/adapters/jdbc/postgresql.rb +58 -48
  64. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  65. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  66. data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
  67. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  68. data/lib/sequel/adapters/jdbc.rb +265 -94
  69. data/lib/sequel/adapters/mock.rb +361 -0
  70. data/lib/sequel/adapters/mysql.rb +118 -222
  71. data/lib/sequel/adapters/mysql2.rb +58 -57
  72. data/lib/sequel/adapters/odbc/mssql.rb +15 -7
  73. data/lib/sequel/adapters/odbc.rb +28 -9
  74. data/lib/sequel/adapters/openbase.rb +3 -5
  75. data/lib/sequel/adapters/oracle.rb +349 -53
  76. data/lib/sequel/adapters/postgres.rb +356 -107
  77. data/lib/sequel/adapters/shared/access.rb +32 -9
  78. data/lib/sequel/adapters/shared/db2.rb +342 -0
  79. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  80. data/lib/sequel/adapters/shared/informix.rb +53 -0
  81. data/lib/sequel/adapters/shared/mssql.rb +335 -118
  82. data/lib/sequel/adapters/shared/mysql.rb +340 -76
  83. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
  84. data/lib/sequel/adapters/shared/oracle.rb +243 -45
  85. data/lib/sequel/adapters/shared/postgres.rb +524 -279
  86. data/lib/sequel/adapters/shared/progress.rb +5 -8
  87. data/lib/sequel/adapters/shared/sqlite.rb +265 -89
  88. data/lib/sequel/adapters/sqlite.rb +101 -39
  89. data/lib/sequel/adapters/swift/mysql.rb +9 -12
  90. data/lib/sequel/adapters/swift/postgres.rb +9 -74
  91. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  92. data/lib/sequel/adapters/swift.rb +8 -7
  93. data/lib/sequel/adapters/tinytds.rb +161 -21
  94. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  95. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  96. data/lib/sequel/ast_transformer.rb +194 -0
  97. data/lib/sequel/connection_pool/sharded_single.rb +11 -1
  98. data/lib/sequel/connection_pool/sharded_threaded.rb +28 -2
  99. data/lib/sequel/connection_pool/single.rb +5 -0
  100. data/lib/sequel/connection_pool/threaded.rb +38 -14
  101. data/lib/sequel/connection_pool.rb +10 -2
  102. data/lib/sequel/core.rb +118 -11
  103. data/lib/sequel/database/connecting.rb +38 -28
  104. data/lib/sequel/database/dataset.rb +4 -4
  105. data/lib/sequel/database/dataset_defaults.rb +63 -2
  106. data/lib/sequel/database/logging.rb +7 -2
  107. data/lib/sequel/database/misc.rb +150 -46
  108. data/lib/sequel/database/query.rb +215 -65
  109. data/lib/sequel/database/schema_generator.rb +64 -20
  110. data/lib/sequel/database/schema_methods.rb +212 -54
  111. data/lib/sequel/dataset/actions.rb +322 -85
  112. data/lib/sequel/dataset/features.rb +96 -8
  113. data/lib/sequel/dataset/graph.rb +38 -11
  114. data/lib/sequel/dataset/misc.rb +50 -23
  115. data/lib/sequel/dataset/mutation.rb +12 -7
  116. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  117. data/lib/sequel/dataset/query.rb +237 -44
  118. data/lib/sequel/dataset/sql.rb +698 -278
  119. data/lib/sequel/dataset.rb +8 -0
  120. data/lib/sequel/exceptions.rb +4 -0
  121. data/lib/sequel/extensions/_pretty_table.rb +79 -0
  122. data/lib/sequel/extensions/arbitrary_servers.rb +108 -0
  123. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  124. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +16 -34
  125. data/lib/sequel/extensions/migration.rb +97 -11
  126. data/lib/sequel/extensions/named_timezones.rb +5 -0
  127. data/lib/sequel/extensions/null_dataset.rb +90 -0
  128. data/lib/sequel/extensions/pg_array.rb +460 -0
  129. data/lib/sequel/extensions/pg_array_ops.rb +220 -0
  130. data/lib/sequel/extensions/pg_auto_parameterize.rb +169 -0
  131. data/lib/sequel/extensions/pg_hstore.rb +296 -0
  132. data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
  133. data/lib/sequel/extensions/pg_inet.rb +89 -0
  134. data/lib/sequel/extensions/pg_json.rb +178 -0
  135. data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
  136. data/lib/sequel/extensions/pretty_table.rb +5 -71
  137. data/lib/sequel/extensions/query.rb +1 -1
  138. data/lib/sequel/extensions/query_literals.rb +79 -0
  139. data/lib/sequel/extensions/schema_caching.rb +76 -0
  140. data/lib/sequel/extensions/schema_dumper.rb +251 -37
  141. data/lib/sequel/extensions/select_remove.rb +35 -0
  142. data/lib/sequel/extensions/server_block.rb +139 -0
  143. data/lib/sequel/extensions/sql_expr.rb +4 -110
  144. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  145. data/lib/sequel/extensions/to_dot.rb +95 -83
  146. data/lib/sequel/model/associations.rb +1187 -393
  147. data/lib/sequel/model/base.rb +578 -170
  148. data/lib/sequel/model/errors.rb +1 -1
  149. data/lib/sequel/model/exceptions.rb +5 -1
  150. data/lib/sequel/model/inflections.rb +1 -1
  151. data/lib/sequel/model.rb +30 -11
  152. data/lib/sequel/no_core_ext.rb +2 -0
  153. data/lib/sequel/plugins/active_model.rb +13 -1
  154. data/lib/sequel/plugins/association_pks.rb +22 -4
  155. data/lib/sequel/plugins/caching.rb +25 -18
  156. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  157. data/lib/sequel/plugins/composition.rb +44 -12
  158. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  159. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  160. data/lib/sequel/plugins/dirty.rb +214 -0
  161. data/lib/sequel/plugins/eager_each.rb +59 -0
  162. data/lib/sequel/plugins/force_encoding.rb +6 -6
  163. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  164. data/lib/sequel/plugins/identity_map.rb +123 -8
  165. data/lib/sequel/plugins/instance_filters.rb +10 -0
  166. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  167. data/lib/sequel/plugins/json_serializer.rb +58 -6
  168. data/lib/sequel/plugins/list.rb +12 -2
  169. data/lib/sequel/plugins/many_through_many.rb +79 -28
  170. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  171. data/lib/sequel/plugins/nested_attributes.rb +139 -63
  172. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  173. data/lib/sequel/plugins/prepared_statements.rb +167 -0
  174. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  175. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  176. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  177. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  178. data/lib/sequel/plugins/schema.rb +7 -2
  179. data/lib/sequel/plugins/serialization.rb +98 -49
  180. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  181. data/lib/sequel/plugins/sharding.rb +21 -54
  182. data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
  183. data/lib/sequel/plugins/static_cache.rb +99 -0
  184. data/lib/sequel/plugins/subclasses.rb +10 -2
  185. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  186. data/lib/sequel/plugins/timestamps.rb +1 -1
  187. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  188. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  189. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  190. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  191. data/lib/sequel/sql.rb +526 -59
  192. data/lib/sequel/timezones.rb +57 -38
  193. data/lib/sequel/version.rb +1 -1
  194. data/spec/adapters/db2_spec.rb +146 -0
  195. data/spec/adapters/firebird_spec.rb +1 -1
  196. data/spec/adapters/mssql_spec.rb +142 -40
  197. data/spec/adapters/mysql_spec.rb +380 -234
  198. data/spec/adapters/oracle_spec.rb +67 -77
  199. data/spec/adapters/postgres_spec.rb +1050 -212
  200. data/spec/adapters/spec_helper.rb +8 -5
  201. data/spec/adapters/sqlite_spec.rb +139 -27
  202. data/spec/core/connection_pool_spec.rb +196 -93
  203. data/spec/core/database_spec.rb +879 -510
  204. data/spec/core/dataset_spec.rb +1415 -1086
  205. data/spec/core/expression_filters_spec.rb +554 -109
  206. data/spec/core/mock_adapter_spec.rb +449 -0
  207. data/spec/core/object_graph_spec.rb +86 -114
  208. data/spec/core/schema_generator_spec.rb +4 -4
  209. data/spec/core/schema_spec.rb +482 -38
  210. data/spec/core/spec_helper.rb +6 -48
  211. data/spec/extensions/active_model_spec.rb +13 -0
  212. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  213. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  214. data/spec/extensions/association_dependencies_spec.rb +15 -25
  215. data/spec/extensions/association_pks_spec.rb +66 -32
  216. data/spec/extensions/association_proxies_spec.rb +4 -4
  217. data/spec/extensions/caching_spec.rb +47 -51
  218. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  219. data/spec/extensions/columns_introspection_spec.rb +91 -0
  220. data/spec/extensions/composition_spec.rb +18 -13
  221. data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +119 -139
  222. data/spec/extensions/dataset_associations_spec.rb +199 -0
  223. data/spec/extensions/defaults_setter_spec.rb +64 -0
  224. data/spec/extensions/dirty_spec.rb +155 -0
  225. data/spec/extensions/eager_each_spec.rb +34 -0
  226. data/spec/extensions/force_encoding_spec.rb +4 -2
  227. data/spec/extensions/hook_class_methods_spec.rb +69 -92
  228. data/spec/extensions/identity_map_spec.rb +131 -22
  229. data/spec/extensions/inflector_spec.rb +0 -4
  230. data/spec/extensions/instance_filters_spec.rb +11 -21
  231. data/spec/extensions/instance_hooks_spec.rb +72 -0
  232. data/spec/extensions/json_serializer_spec.rb +49 -6
  233. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  234. data/spec/extensions/list_spec.rb +48 -39
  235. data/spec/extensions/many_through_many_spec.rb +283 -250
  236. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  237. data/spec/extensions/migration_spec.rb +140 -35
  238. data/spec/extensions/named_timezones_spec.rb +29 -11
  239. data/spec/extensions/nested_attributes_spec.rb +251 -89
  240. data/spec/extensions/null_dataset_spec.rb +85 -0
  241. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  242. data/spec/extensions/pg_array_ops_spec.rb +105 -0
  243. data/spec/extensions/pg_array_spec.rb +196 -0
  244. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  245. data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
  246. data/spec/extensions/pg_hstore_spec.rb +195 -0
  247. data/spec/extensions/pg_inet_spec.rb +44 -0
  248. data/spec/extensions/pg_json_spec.rb +101 -0
  249. data/spec/extensions/pg_statement_cache_spec.rb +209 -0
  250. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  251. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  252. data/spec/extensions/prepared_statements_spec.rb +87 -0
  253. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  254. data/spec/extensions/pretty_table_spec.rb +7 -6
  255. data/spec/extensions/query_literals_spec.rb +168 -0
  256. data/spec/extensions/query_spec.rb +6 -0
  257. data/spec/extensions/rcte_tree_spec.rb +50 -43
  258. data/spec/extensions/schema_caching_spec.rb +41 -0
  259. data/spec/extensions/schema_dumper_spec.rb +429 -22
  260. data/spec/extensions/schema_spec.rb +25 -21
  261. data/spec/extensions/select_remove_spec.rb +38 -0
  262. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  263. data/spec/extensions/serialization_spec.rb +85 -43
  264. data/spec/extensions/server_block_spec.rb +90 -0
  265. data/spec/extensions/sharding_spec.rb +69 -143
  266. data/spec/extensions/single_table_inheritance_spec.rb +23 -29
  267. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  268. data/spec/extensions/spec_helper.rb +22 -61
  269. data/spec/extensions/sql_expr_spec.rb +29 -60
  270. data/spec/extensions/static_cache_spec.rb +145 -0
  271. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  272. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  273. data/spec/extensions/timestamps_spec.rb +6 -6
  274. data/spec/extensions/to_dot_spec.rb +4 -7
  275. data/spec/extensions/touch_spec.rb +13 -14
  276. data/spec/extensions/tree_spec.rb +11 -26
  277. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  278. data/spec/extensions/update_primary_key_spec.rb +30 -24
  279. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  280. data/spec/extensions/validation_helpers_spec.rb +16 -35
  281. data/spec/extensions/xml_serializer_spec.rb +29 -4
  282. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  283. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  284. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  285. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  286. data/spec/integration/associations_test.rb +659 -21
  287. data/spec/integration/database_test.rb +9 -3
  288. data/spec/integration/dataset_test.rb +605 -91
  289. data/spec/integration/eager_loader_test.rb +19 -21
  290. data/spec/integration/migrator_test.rb +2 -3
  291. data/spec/integration/model_test.rb +81 -2
  292. data/spec/integration/plugin_test.rb +454 -143
  293. data/spec/integration/prepared_statement_test.rb +263 -128
  294. data/spec/integration/schema_test.rb +309 -43
  295. data/spec/integration/spec_helper.rb +40 -30
  296. data/spec/integration/timezone_test.rb +38 -12
  297. data/spec/integration/transaction_test.rb +183 -8
  298. data/spec/integration/type_test.rb +18 -4
  299. data/spec/model/association_reflection_spec.rb +201 -7
  300. data/spec/model/associations_spec.rb +1067 -661
  301. data/spec/model/base_spec.rb +329 -95
  302. data/spec/model/dataset_methods_spec.rb +7 -27
  303. data/spec/model/eager_loading_spec.rb +677 -676
  304. data/spec/model/hooks_spec.rb +349 -67
  305. data/spec/model/model_spec.rb +240 -168
  306. data/spec/model/plugins_spec.rb +24 -13
  307. data/spec/model/record_spec.rb +490 -232
  308. data/spec/model/spec_helper.rb +14 -71
  309. data/spec/model/validations_spec.rb +11 -0
  310. data/spec/rcov.opts +2 -0
  311. metadata +178 -80
@@ -1,17 +1,20 @@
1
1
  module Sequel
2
2
  class Dataset
3
3
  # ---------------------
4
- # :section: Methods that describe what the dataset supports
4
+ # :section: 4 - Methods that describe what the dataset supports
5
5
  # These methods all return booleans, with most describing whether or not the
6
6
  # dataset supports a feature.
7
7
  # ---------------------
8
8
 
9
- # Method used to check if WITH is supported
10
- WITH_SUPPORTED=:select_with_sql
11
-
12
9
  # Whether this dataset quotes identifiers.
13
10
  def quote_identifiers?
14
- @quote_identifiers
11
+ if defined?(@quote_identifiers)
12
+ @quote_identifiers
13
+ elsif db.respond_to?(:quote_identifiers?)
14
+ @quote_identifiers = db.quote_identifiers?
15
+ else
16
+ @quote_identifiers = false
17
+ end
15
18
  end
16
19
 
17
20
  # Whether this dataset will provide accurate number of rows matched for
@@ -21,22 +24,59 @@ module Sequel
21
24
  true
22
25
  end
23
26
 
27
+ # Whether you must use a column alias list for recursive CTEs (false by
28
+ # default).
29
+ def recursive_cte_requires_column_aliases?
30
+ false
31
+ end
32
+
24
33
  # Whether the dataset requires SQL standard datetimes (false by default,
25
34
  # as most allow strings with ISO 8601 format).
26
35
  def requires_sql_standard_datetimes?
27
36
  false
28
37
  end
29
38
 
39
+ # Whether type specifiers are required for prepared statement/bound
40
+ # variable argument placeholders (i.e. :bv__integer)
41
+ def requires_placeholder_type_specifiers?
42
+ false
43
+ end
44
+
30
45
  # Whether the dataset supports common table expressions (the WITH clause).
31
- def supports_cte?
32
- select_clause_methods.include?(WITH_SUPPORTED)
46
+ # If given, +type+ can be :select, :insert, :update, or :delete, in which case it
47
+ # determines whether WITH is supported for the respective statement type.
48
+ def supports_cte?(type=:select)
49
+ send(:"#{type}_clause_methods").include?(:"#{type}_with_sql")
50
+ end
51
+
52
+ # Whether the dataset supports common table expressions (the WITH clause)
53
+ # in subqueries. If false, applies the WITH clause to the main query, which can cause issues
54
+ # if multiple WITH clauses use the same name.
55
+ def supports_cte_in_subqueries?
56
+ false
33
57
  end
34
58
 
35
- # Whether the dataset supports the DISTINCT ON clause, false by default.
59
+ # Whether the dataset supports or can emulate the DISTINCT ON clause, false by default.
36
60
  def supports_distinct_on?
37
61
  false
38
62
  end
39
63
 
64
+ # Whether the dataset supports CUBE with GROUP BY.
65
+ def supports_group_cube?
66
+ false
67
+ end
68
+
69
+ # Whether the dataset supports ROLLUP with GROUP BY.
70
+ def supports_group_rollup?
71
+ false
72
+ end
73
+
74
+ # Whether this dataset supports the +insert_select+ method for returning all columns values
75
+ # directly from an insert query.
76
+ def supports_insert_select?
77
+ supports_returning?(:insert)
78
+ end
79
+
40
80
  # Whether the dataset supports the INTERSECT and EXCEPT compound operations, true by default.
41
81
  def supports_intersect_except?
42
82
  true
@@ -67,7 +107,24 @@ module Sequel
67
107
  def supports_multiple_column_in?
68
108
  true
69
109
  end
110
+
111
+ # Whether the dataset supports or can fully emulate the DISTINCT ON clause,
112
+ # including respecting the ORDER BY clause, false by default
113
+ def supports_ordered_distinct_on?
114
+ supports_distinct_on?
115
+ end
70
116
 
117
+ # Whether the RETURNING clause is supported for the given type of query.
118
+ # +type+ can be :insert, :update, or :delete.
119
+ def supports_returning?(type)
120
+ send(:"#{type}_clause_methods").include?(:"#{type}_returning_sql")
121
+ end
122
+
123
+ # Whether the database supports SELECT *, column FROM table
124
+ def supports_select_all_and_column?
125
+ true
126
+ end
127
+
71
128
  # Whether the dataset supports timezones in literal timestamps
72
129
  def supports_timestamp_timezones?
73
130
  false
@@ -82,5 +139,36 @@ module Sequel
82
139
  def supports_window_functions?
83
140
  false
84
141
  end
142
+
143
+ # Whether the dataset supports WHERE TRUE (or WHERE 1 for databases that
144
+ # that use 1 for true).
145
+ def supports_where_true?
146
+ true
147
+ end
148
+
149
+ private
150
+
151
+ # Whether insert(nil) or insert({}) must be emulated by
152
+ # using at least one value, false by default.
153
+ def insert_supports_empty_values?
154
+ true
155
+ end
156
+
157
+ # Whether using an offset returns an extra row number column that should be
158
+ # eliminated, false by default.
159
+ def offset_returns_row_number_column?
160
+ false
161
+ end
162
+
163
+ # Whether the RETURNING clause is used for the given dataset.
164
+ # +type+ can be :insert, :update, or :delete.
165
+ def uses_returning?(type)
166
+ opts[:returning] && !@opts[:sql] && supports_returning?(type)
167
+ end
168
+
169
+ # Whether the dataset uses WITH ROLLUP/CUBE instead of ROLLUP()/CUBE().
170
+ def uses_with_rollup?
171
+ false
172
+ end
85
173
  end
86
174
  end
@@ -1,7 +1,7 @@
1
1
  module Sequel
2
2
  class Dataset
3
3
  # ---------------------
4
- # :section: Methods related to dataset graphing
4
+ # :section: 5 - Methods related to dataset graphing
5
5
  # Dataset graphing changes the dataset to yield hashes where keys are table
6
6
  # name symbols and values are hashes representing the columns related to
7
7
  # that table. All of these methods return modified copies of the receiver.
@@ -115,7 +115,11 @@ module Sequel
115
115
  add_columns = !ds.opts.include?(:graph_aliases)
116
116
 
117
117
  # Setup the initial graph data structure if it doesn't exist
118
- unless graph = opts[:graph]
118
+ if graph = opts[:graph]
119
+ opts[:graph] = graph = graph.dup
120
+ select = opts[:select].dup
121
+ [:column_aliases, :table_aliases, :column_alias_num].each{|k| graph[k] = graph[k].dup}
122
+ else
119
123
  master = alias_symbol(ds.first_source_alias)
120
124
  raise_alias_error.call if master == table_alias
121
125
  # Master hash storing all .graph related information
@@ -130,10 +134,33 @@ module Sequel
130
134
  # aliased, but are not included if set_graph_aliases
131
135
  # has been used.
132
136
  if add_columns
133
- select = opts[:select] = []
134
- columns.each do |column|
135
- column_aliases[column] = [master, column]
136
- select.push(SQL::QualifiedIdentifier.new(master, column))
137
+ if (select = @opts[:select]) && !select.empty? && !(select.length == 1 && (select.first.is_a?(SQL::ColumnAll)))
138
+ select = select.each do |sel|
139
+ column = case sel
140
+ when Symbol
141
+ _, c, a = split_symbol(sel)
142
+ (a || c).to_sym
143
+ when SQL::Identifier
144
+ sel.value.to_sym
145
+ when SQL::QualifiedIdentifier
146
+ column = sel.column
147
+ column = column.value if column.is_a?(SQL::Identifier)
148
+ column.to_sym
149
+ when SQL::AliasedExpression
150
+ column = sel.aliaz
151
+ column = column.value if column.is_a?(SQL::Identifier)
152
+ column.to_sym
153
+ else
154
+ raise Error, "can't figure out alias to use for graphing for #{sel.inspect}"
155
+ end
156
+ column_aliases[column] = [master, column]
157
+ end
158
+ select = qualified_expression(select, master)
159
+ else
160
+ select = columns.map do |column|
161
+ column_aliases[column] = [master, column]
162
+ SQL::QualifiedIdentifier.new(master, column)
163
+ end
137
164
  end
138
165
  end
139
166
  end
@@ -147,7 +174,6 @@ module Sequel
147
174
 
148
175
  # Add the columns to the selection unless we are ignoring them
149
176
  if add_table && add_columns
150
- select = opts[:select]
151
177
  column_aliases = graph[:column_aliases]
152
178
  ca_num = graph[:column_alias_num]
153
179
  # Which columns to add to the result set
@@ -165,15 +191,16 @@ module Sequel
165
191
  column_alias = :"#{column_alias}_#{column_alias_num}"
166
192
  ca_num[column_alias] += 1
167
193
  end
168
- [column_alias, SQL::QualifiedIdentifier.new(table_alias, column).as(column_alias)]
194
+ [column_alias, SQL::AliasedExpression.new(SQL::QualifiedIdentifier.new(table_alias, column), column_alias)]
169
195
  else
170
- [column, SQL::QualifiedIdentifier.new(table_alias, column)]
196
+ ident = SQL::QualifiedIdentifier.new(table_alias, column)
197
+ [column, ident]
171
198
  end
172
199
  column_aliases[col_alias] = [table_alias, column]
173
200
  select.push(identifier)
174
201
  end
175
202
  end
176
- ds
203
+ add_columns ? ds.select(*select) : ds
177
204
  end
178
205
 
179
206
  # This allows you to manually specify the graph aliases to use
@@ -225,7 +252,7 @@ module Sequel
225
252
  column ||= col_alias
226
253
  gas[col_alias] = [table, column]
227
254
  identifier = value || SQL::QualifiedIdentifier.new(table, column)
228
- identifier = SQL::AliasedExpression.new(identifier, col_alias) if value or column != col_alias
255
+ identifier = SQL::AliasedExpression.new(identifier, col_alias) if value || column != col_alias
229
256
  identifier
230
257
  end
231
258
  [identifiers, gas]
@@ -1,7 +1,7 @@
1
1
  module Sequel
2
2
  class Dataset
3
3
  # ---------------------
4
- # :section: Miscellaneous methods
4
+ # :section: 6 - Miscellaneous methods
5
5
  # These methods don't fit cleanly into another section.
6
6
  # ---------------------
7
7
 
@@ -23,17 +23,13 @@ module Sequel
23
23
  # DB[:posts]
24
24
  #
25
25
  # Sequel::Dataset is an abstract class that is not useful by itself. Each
26
- # database adaptor provides a subclass of Sequel::Dataset, and has
26
+ # database adapter provides a subclass of Sequel::Dataset, and has
27
27
  # the Database#dataset method return an instance of that subclass.
28
28
  def initialize(db, opts = nil)
29
29
  @db = db
30
- @quote_identifiers = db.quote_identifiers? if db.respond_to?(:quote_identifiers?)
31
- @identifier_input_method = db.identifier_input_method if db.respond_to?(:identifier_input_method)
32
- @identifier_output_method = db.identifier_output_method if db.respond_to?(:identifier_output_method)
33
30
  @opts = opts || {}
34
- @row_proc = nil
35
31
  end
36
-
32
+
37
33
  # Define a hash value such that datasets with the same DB, opts, and SQL
38
34
  # will be consider equal.
39
35
  def ==(o)
@@ -45,15 +41,6 @@ module Sequel
45
41
  self == o
46
42
  end
47
43
 
48
- # Return the dataset as an aliased expression with the given alias. You can
49
- # use this as a FROM or JOIN dataset, or as a column if this dataset
50
- # returns a single row and column.
51
- #
52
- # DB.from(DB[:table].as(:b)) # SELECT * FROM (SELECT * FROM table) AS b
53
- def as(aliaz)
54
- ::Sequel::SQL::AliasedExpression.new(self, aliaz)
55
- end
56
-
57
44
  # Yield a dataset for each server in the connection pool that is tied to that server.
58
45
  # Intended for use in sharded environments where all servers need to be modified
59
46
  # with the same data:
@@ -96,10 +83,10 @@ module Sequel
96
83
  # have a table, raises an error. If the table is aliased, returns the original
97
84
  # table, not the alias
98
85
  #
99
- # DB[:table].first_source_alias
86
+ # DB[:table].first_source_table
100
87
  # # => :table
101
88
  #
102
- # DB[:table___t].first_source_alias
89
+ # DB[:table___t].first_source_table
103
90
  # # => :table
104
91
  def first_source_table
105
92
  source = @opts[:from]
@@ -120,16 +107,48 @@ module Sequel
120
107
  # Define a hash value such that datasets with the same DB, opts, and SQL
121
108
  # will have the same hash value
122
109
  def hash
123
- [db, opts.sort_by{|k| k.to_s}, sql].hash
110
+ [db, opts.sort_by{|k, v| k.to_s}, sql].hash
111
+ end
112
+
113
+ # The String instance method to call on identifiers before sending them to
114
+ # the database.
115
+ def identifier_input_method
116
+ if defined?(@identifier_input_method)
117
+ @identifier_input_method
118
+ elsif db.respond_to?(:identifier_input_method)
119
+ @identifier_input_method = db.identifier_input_method
120
+ else
121
+ @identifier_input_method = nil
122
+ end
123
+ end
124
+
125
+ # The String instance method to call on identifiers before sending them to
126
+ # the database.
127
+ def identifier_output_method
128
+ if defined?(@identifier_output_method)
129
+ @identifier_output_method
130
+ elsif db.respond_to?(:identifier_output_method)
131
+ @identifier_output_method = db.identifier_output_method
132
+ else
133
+ @identifier_output_method = nil
134
+ end
124
135
  end
125
136
 
126
137
  # Returns a string representation of the dataset including the class name
127
138
  # and the corresponding SQL select statement.
128
139
  def inspect
129
- "#<#{self.class}: #{sql.inspect}>"
140
+ c = self.class
141
+ c = c.superclass while c.name.nil? || c.name == ''
142
+ "#<#{c.name}: #{sql.inspect}>"
130
143
  end
131
144
 
132
- # Splits a possible implicit alias in C, handling both SQL::AliasedExpressions
145
+ # The alias to use for the row_number column, used when emulating OFFSET
146
+ # support and for eager limit strategies
147
+ def row_number_column
148
+ :x_sequel_row_number_x
149
+ end
150
+
151
+ # Splits a possible implicit alias in +c+, handling both SQL::AliasedExpressions
133
152
  # and Symbols. Returns an array of two elements, with the first being the
134
153
  # main expression, and the second being the alias.
135
154
  def split_alias(c)
@@ -139,6 +158,8 @@ module Sequel
139
158
  [c_table ? SQL::QualifiedIdentifier.new(c_table, column.to_sym) : column.to_sym, aliaz]
140
159
  when SQL::AliasedExpression
141
160
  [c.expression, c.aliaz]
161
+ when SQL::JoinClause
162
+ [c.table, c.table_alias]
142
163
  else
143
164
  [c, nil]
144
165
  end
@@ -151,6 +172,10 @@ module Sequel
151
172
  # used, where N is an integer starting at 0 and increasing until an
152
173
  # unused one is found.
153
174
  #
175
+ # You can provide a second addition array argument containing symbols
176
+ # that should not be considered valid table aliases. The current aliases
177
+ # for the FROM and JOIN tables are automatically included in this array.
178
+ #
154
179
  # DB[:table].unused_table_alias(:t)
155
180
  # # => :t
156
181
  #
@@ -159,9 +184,11 @@ module Sequel
159
184
  #
160
185
  # DB[:table, :table_0].unused_table_alias(:table)
161
186
  # # => :table_1
162
- def unused_table_alias(table_alias)
187
+ #
188
+ # DB[:table, :table_0].unused_table_alias(:table, [:table_1, :table_2])
189
+ # # => :table_3
190
+ def unused_table_alias(table_alias, used_aliases = [])
163
191
  table_alias = alias_symbol(table_alias)
164
- used_aliases = []
165
192
  used_aliases += opts[:from].map{|t| alias_symbol(t)} if opts[:from]
166
193
  used_aliases += opts[:join].map{|j| j.table_alias ? alias_alias_symbol(j.table_alias) : alias_symbol(j.table)} if opts[:join]
167
194
  if used_aliases.include?(table_alias)
@@ -1,12 +1,12 @@
1
1
  module Sequel
2
2
  class Dataset
3
3
  # ---------------------
4
- # :section: Mutation methods
4
+ # :section: 7 - Mutation methods
5
5
  # These methods modify the receiving dataset and should be used with care.
6
6
  # ---------------------
7
7
 
8
8
  # All methods that should have a ! method added that modifies the receiver.
9
- MUTATION_METHODS = QUERY_METHODS
9
+ MUTATION_METHODS = QUERY_METHODS - [:paginate, :naked]
10
10
 
11
11
  # Setup mutation (e.g. filter!) methods. These operate the same as the
12
12
  # non-! methods, but replace the options of the current dataset with the
@@ -21,17 +21,16 @@ module Sequel
21
21
  def_mutation_method(*MUTATION_METHODS)
22
22
 
23
23
  # Set the method to call on identifiers going into the database for this dataset
24
- attr_accessor :identifier_input_method
24
+ attr_writer :identifier_input_method
25
25
 
26
26
  # Set the method to call on identifiers coming the database for this dataset
27
- attr_accessor :identifier_output_method
27
+ attr_writer :identifier_output_method
28
28
 
29
29
  # Whether to quote identifiers for this dataset
30
30
  attr_writer :quote_identifiers
31
31
 
32
- # The row_proc for this database, should be a Proc that takes
33
- # a single hash argument and returns the object you want
34
- # each to return.
32
+ # The row_proc for this database, should be any object that responds to +call+ with
33
+ # a single hash argument and returns the object you want #each to return.
35
34
  attr_accessor :row_proc
36
35
 
37
36
  # Add a mutation method to this dataset instance.
@@ -40,6 +39,12 @@ module Sequel
40
39
  instance_eval("def #{meth}!(*args, &block); mutation_method(:#{meth}, *args, &block) end", __FILE__, __LINE__)
41
40
  end
42
41
  end
42
+
43
+ # Remove the row_proc from the current dataset.
44
+ def naked!
45
+ self.row_proc = nil
46
+ self
47
+ end
43
48
 
44
49
  private
45
50
 
@@ -1,7 +1,7 @@
1
1
  module Sequel
2
2
  class Dataset
3
3
  # ---------------------
4
- # :section: Methods related to prepared statements or bound variables
4
+ # :section: 8 - Methods related to prepared statements or bound variables
5
5
  # On some adapters, these use native prepared statements and bound variables, on others
6
6
  # support is emulated. For details, see the {"Prepared Statements/Bound Variables" guide}[link:files/doc/prepared_statements_rdoc.html].
7
7
  # ---------------------
@@ -12,15 +12,12 @@ module Sequel
12
12
  # native database support for bind variables and prepared
13
13
  # statements (as opposed to the emulated ones used by default).
14
14
  module ArgumentMapper
15
- SQL_QUERY_TYPE = Hash.new{|h,k| h[k] = k}
16
- SQL_QUERY_TYPE[:first] = SQL_QUERY_TYPE[:all] = :select
17
-
18
15
  # The name of the prepared statement, if any.
19
16
  attr_accessor :prepared_statement_name
20
17
 
21
18
  # The bind arguments to use for running this prepared statement
22
19
  attr_accessor :bind_arguments
23
-
20
+
24
21
  # Set the bind arguments based on the hash and call super.
25
22
  def call(bind_vars={}, &block)
26
23
  ds = bind(bind_vars)
@@ -35,16 +32,9 @@ module Sequel
35
32
  return @prepared_sql if @prepared_sql
36
33
  @prepared_args ||= []
37
34
  @prepared_sql = super
38
- meta_def("#{sql_query_type}_sql"){|*args| prepared_sql}
35
+ @opts[:sql] = @prepared_sql
39
36
  @prepared_sql
40
37
  end
41
-
42
- private
43
-
44
- # The type of query (:select, :insert, :delete, :update).
45
- def sql_query_type
46
- SQL_QUERY_TYPE[@prepared_type]
47
- end
48
38
  end
49
39
 
50
40
  # Backbone of the prepared statement support. Grafts bind variable
@@ -56,6 +46,10 @@ module Sequel
56
46
  module PreparedStatementMethods
57
47
  PLACEHOLDER_RE = /\A\$(.*)\z/
58
48
 
49
+ # Whether to log the full SQL query. By default, just the prepared statement
50
+ # name is generally logged on adapters that support native prepared statements.
51
+ attr_accessor :log_sql
52
+
59
53
  # The type of prepared statement, should be one of :select, :first,
60
54
  # :insert, :update, or :delete
61
55
  attr_accessor :prepared_type
@@ -63,6 +57,9 @@ module Sequel
63
57
  # The array/hash of bound variable placeholder names.
64
58
  attr_accessor :prepared_args
65
59
 
60
+ # The dataset that created this prepared statement.
61
+ attr_accessor :orig_dataset
62
+
66
63
  # The argument to supply to insert and update, which may use
67
64
  # placeholders specified by prepared_args
68
65
  attr_accessor :prepared_modify_values
@@ -72,31 +69,46 @@ module Sequel
72
69
  def call(bind_vars={}, &block)
73
70
  bind(bind_vars).run(&block)
74
71
  end
72
+
73
+ # Send the columns to the original dataset, as calling it
74
+ # on the prepared statement can cause problems.
75
+ def columns
76
+ orig_dataset.columns
77
+ end
75
78
 
76
79
  # Returns the SQL for the prepared statement, depending on
77
80
  # the type of the statement and the prepared_modify_values.
78
81
  def prepared_sql
79
82
  case @prepared_type
80
- when :select, :all
83
+ when :select, :all, :each
84
+ # Most common scenario, so listed first.
81
85
  select_sql
82
86
  when :first
83
87
  clone(:limit=>1).select_sql
88
+ when :insert_select
89
+ returning.insert_sql(*@prepared_modify_values)
84
90
  when :insert
85
91
  insert_sql(*@prepared_modify_values)
86
92
  when :update
87
93
  update_sql(*@prepared_modify_values)
88
94
  when :delete
89
95
  delete_sql
96
+ else
97
+ select_sql
90
98
  end
91
99
  end
92
100
 
93
101
  # Changes the values of symbols if they start with $ and
94
102
  # prepared_args is present. If so, they are considered placeholders,
95
103
  # and they are substituted using prepared_arg.
96
- def literal_symbol(v)
104
+ def literal_symbol_append(sql, v)
97
105
  if @opts[:bind_vars] and match = PLACEHOLDER_RE.match(v.to_s)
98
- v2 = prepared_arg(match[1].to_sym)
99
- v2 ? literal(v2) : v
106
+ s = match[1].to_sym
107
+ if prepared_arg?(s)
108
+ literal_append(sql, prepared_arg(s))
109
+ else
110
+ sql << v.to_s
111
+ end
100
112
  else
101
113
  super
102
114
  end
@@ -117,7 +129,12 @@ module Sequel
117
129
  def run(&block)
118
130
  case @prepared_type
119
131
  when :select, :all
132
+ # Most common scenario, so listed first
120
133
  all(&block)
134
+ when :each
135
+ each(&block)
136
+ when :insert_select
137
+ with_sql(prepared_sql).first
121
138
  when :first
122
139
  first
123
140
  when :insert
@@ -126,6 +143,13 @@ module Sequel
126
143
  update(*@prepared_modify_values)
127
144
  when :delete
128
145
  delete
146
+ when Array
147
+ case @prepared_type.at(0)
148
+ when :map, :to_hash, :to_hash_groups
149
+ send(*@prepared_type, &block)
150
+ end
151
+ else
152
+ all(&block)
129
153
  end
130
154
  end
131
155
 
@@ -136,11 +160,16 @@ module Sequel
136
160
  @opts[:bind_vars][k]
137
161
  end
138
162
 
163
+ # Whether there is a bound value for the given key.
164
+ def prepared_arg?(k)
165
+ @opts[:bind_vars].has_key?(k)
166
+ end
167
+
139
168
  # Use a clone of the dataset extended with prepared statement
140
169
  # support and using the same argument hash so that you can use
141
170
  # bind variables/prepared arguments in subselects.
142
- def subselect_sql(ds)
143
- ps = ds.prepare(:select)
171
+ def subselect_sql_append(sql, ds)
172
+ ps = ds.clone(:append_sql=>sql).prepare(:select)
144
173
  ps = ps.bind(@opts[:bind_vars]) if @opts[:bind_vars]
145
174
  ps.prepared_args = prepared_args
146
175
  ps.prepared_sql
@@ -171,6 +200,11 @@ module Sequel
171
200
  prepared_args << k
172
201
  prepared_arg_placeholder
173
202
  end
203
+
204
+ # Always assume there is a prepared arg in the argument mapper.
205
+ def prepared_arg?(k)
206
+ true
207
+ end
174
208
  end
175
209
 
176
210
  # Set the bind variables to use for the call. If bind variables have
@@ -184,11 +218,9 @@ module Sequel
184
218
  clone(:bind_vars=>@opts[:bind_vars] ? @opts[:bind_vars].merge(bind_vars) : bind_vars)
185
219
  end
186
220
 
187
- # For the given type (:select, :insert, :update, or :delete),
188
- # run the sql with the bind variables
189
- # specified in the hash. values is a hash of passed to
190
- # insert or update (if one of those types is used),
191
- # which may contain placeholders.
221
+ # For the given type (:select, :first, :insert, :insert_select, :update, or :delete),
222
+ # run the sql with the bind variables specified in the hash. +values+ is a hash passed to
223
+ # insert or update (if one of those types is used), which may contain placeholders.
192
224
  #
193
225
  # DB[:table].filter(:id=>:$id).call(:first, :id=>1)
194
226
  # # SELECT * FROM table WHERE id = ? LIMIT 1 -- (1)
@@ -197,11 +229,16 @@ module Sequel
197
229
  prepare(type, nil, *values).call(bind_variables, &block)
198
230
  end
199
231
 
200
- # Prepare an SQL statement for later execution. This returns
201
- # a clone of the dataset extended with PreparedStatementMethods,
202
- # on which you can call call with the hash of bind variables to
203
- # do substitution. The prepared statement is also stored in
204
- # the associated database. The following usage is identical:
232
+ # Prepare an SQL statement for later execution. Takes a type similar to #call,
233
+ # and the +name+ symbol of the prepared statement. While +name+ defaults to +nil+,
234
+ # it should always be provided as a symbol for the name of the prepared statement,
235
+ # as some databases require that prepared statements have names.
236
+ #
237
+ # This returns a clone of the dataset extended with PreparedStatementMethods,
238
+ # which you can +call+ with the hash of bind variables to use.
239
+ # The prepared statement is also stored in
240
+ # the associated database, where it can be called by name.
241
+ # The following usage is identical:
205
242
  #
206
243
  # ps = DB[:table].filter(:name=>:$name).prepare(:first, :select_by_name)
207
244
  #
@@ -212,7 +249,7 @@ module Sequel
212
249
  # DB.call(:select_by_name, :name=>'Blah') # Same thing
213
250
  def prepare(type, name=nil, *values)
214
251
  ps = to_prepared_statement(type, values)
215
- db.prepared_statements[name] = ps if name
252
+ db.set_prepared_statement(name, ps) if name
216
253
  ps
217
254
  end
218
255
 
@@ -223,6 +260,7 @@ module Sequel
223
260
  def to_prepared_statement(type, values=nil)
224
261
  ps = bind
225
262
  ps.extend(PreparedStatementMethods)
263
+ ps.orig_dataset = self
226
264
  ps.prepared_type = type
227
265
  ps.prepared_modify_values = values
228
266
  ps