sequel 5.39.0 → 5.63.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 (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +308 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +57 -25
  5. data/bin/sequel +11 -3
  6. data/doc/advanced_associations.rdoc +13 -13
  7. data/doc/association_basics.rdoc +89 -24
  8. data/doc/cheat_sheet.rdoc +11 -3
  9. data/doc/migration.rdoc +12 -6
  10. data/doc/model_hooks.rdoc +1 -1
  11. data/doc/object_model.rdoc +8 -8
  12. data/doc/opening_databases.rdoc +18 -11
  13. data/doc/postgresql.rdoc +16 -8
  14. data/doc/querying.rdoc +5 -3
  15. data/doc/release_notes/5.40.0.txt +40 -0
  16. data/doc/release_notes/5.41.0.txt +25 -0
  17. data/doc/release_notes/5.42.0.txt +136 -0
  18. data/doc/release_notes/5.43.0.txt +98 -0
  19. data/doc/release_notes/5.44.0.txt +32 -0
  20. data/doc/release_notes/5.45.0.txt +34 -0
  21. data/doc/release_notes/5.46.0.txt +87 -0
  22. data/doc/release_notes/5.47.0.txt +59 -0
  23. data/doc/release_notes/5.48.0.txt +14 -0
  24. data/doc/release_notes/5.49.0.txt +59 -0
  25. data/doc/release_notes/5.50.0.txt +78 -0
  26. data/doc/release_notes/5.51.0.txt +47 -0
  27. data/doc/release_notes/5.52.0.txt +87 -0
  28. data/doc/release_notes/5.53.0.txt +23 -0
  29. data/doc/release_notes/5.54.0.txt +27 -0
  30. data/doc/release_notes/5.55.0.txt +21 -0
  31. data/doc/release_notes/5.56.0.txt +51 -0
  32. data/doc/release_notes/5.57.0.txt +23 -0
  33. data/doc/release_notes/5.58.0.txt +31 -0
  34. data/doc/release_notes/5.59.0.txt +73 -0
  35. data/doc/release_notes/5.60.0.txt +22 -0
  36. data/doc/release_notes/5.61.0.txt +43 -0
  37. data/doc/release_notes/5.62.0.txt +132 -0
  38. data/doc/release_notes/5.63.0.txt +33 -0
  39. data/doc/schema_modification.rdoc +1 -1
  40. data/doc/security.rdoc +9 -9
  41. data/doc/sql.rdoc +27 -15
  42. data/doc/testing.rdoc +22 -11
  43. data/doc/transactions.rdoc +6 -6
  44. data/doc/virtual_rows.rdoc +2 -2
  45. data/lib/sequel/adapters/ado/access.rb +1 -1
  46. data/lib/sequel/adapters/ado.rb +17 -17
  47. data/lib/sequel/adapters/amalgalite.rb +3 -5
  48. data/lib/sequel/adapters/ibmdb.rb +2 -2
  49. data/lib/sequel/adapters/jdbc/derby.rb +8 -0
  50. data/lib/sequel/adapters/jdbc/h2.rb +60 -10
  51. data/lib/sequel/adapters/jdbc/hsqldb.rb +6 -0
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +4 -4
  53. data/lib/sequel/adapters/jdbc.rb +16 -18
  54. data/lib/sequel/adapters/mysql.rb +80 -67
  55. data/lib/sequel/adapters/mysql2.rb +54 -49
  56. data/lib/sequel/adapters/odbc.rb +6 -2
  57. data/lib/sequel/adapters/oracle.rb +3 -3
  58. data/lib/sequel/adapters/postgres.rb +83 -40
  59. data/lib/sequel/adapters/shared/access.rb +11 -1
  60. data/lib/sequel/adapters/shared/db2.rb +30 -0
  61. data/lib/sequel/adapters/shared/mssql.rb +58 -7
  62. data/lib/sequel/adapters/shared/mysql.rb +40 -2
  63. data/lib/sequel/adapters/shared/oracle.rb +76 -0
  64. data/lib/sequel/adapters/shared/postgres.rb +418 -174
  65. data/lib/sequel/adapters/shared/sqlanywhere.rb +10 -0
  66. data/lib/sequel/adapters/shared/sqlite.rb +102 -11
  67. data/lib/sequel/adapters/sqlanywhere.rb +1 -1
  68. data/lib/sequel/adapters/sqlite.rb +60 -18
  69. data/lib/sequel/adapters/tinytds.rb +1 -1
  70. data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
  71. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
  72. data/lib/sequel/ast_transformer.rb +6 -0
  73. data/lib/sequel/connection_pool/sharded_single.rb +5 -7
  74. data/lib/sequel/connection_pool/sharded_threaded.rb +5 -1
  75. data/lib/sequel/connection_pool/single.rb +6 -8
  76. data/lib/sequel/connection_pool/threaded.rb +8 -8
  77. data/lib/sequel/connection_pool/timed_queue.rb +257 -0
  78. data/lib/sequel/connection_pool.rb +47 -30
  79. data/lib/sequel/core.rb +28 -18
  80. data/lib/sequel/database/connecting.rb +26 -2
  81. data/lib/sequel/database/misc.rb +69 -14
  82. data/lib/sequel/database/query.rb +38 -1
  83. data/lib/sequel/database/schema_generator.rb +45 -52
  84. data/lib/sequel/database/schema_methods.rb +17 -1
  85. data/lib/sequel/dataset/actions.rb +107 -13
  86. data/lib/sequel/dataset/features.rb +20 -0
  87. data/lib/sequel/dataset/misc.rb +1 -1
  88. data/lib/sequel/dataset/prepared_statements.rb +2 -0
  89. data/lib/sequel/dataset/query.rb +118 -16
  90. data/lib/sequel/dataset/sql.rb +177 -47
  91. data/lib/sequel/extensions/_model_pg_row.rb +0 -12
  92. data/lib/sequel/extensions/_pretty_table.rb +1 -1
  93. data/lib/sequel/extensions/any_not_empty.rb +1 -1
  94. data/lib/sequel/extensions/async_thread_pool.rb +438 -0
  95. data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
  96. data/lib/sequel/extensions/blank.rb +8 -0
  97. data/lib/sequel/extensions/constraint_validations.rb +1 -1
  98. data/lib/sequel/extensions/core_refinements.rb +36 -11
  99. data/lib/sequel/extensions/date_arithmetic.rb +71 -31
  100. data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
  101. data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
  102. data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
  103. data/lib/sequel/extensions/eval_inspect.rb +2 -0
  104. data/lib/sequel/extensions/inflector.rb +9 -1
  105. data/lib/sequel/extensions/is_distinct_from.rb +141 -0
  106. data/lib/sequel/extensions/looser_typecasting.rb +3 -0
  107. data/lib/sequel/extensions/migration.rb +7 -2
  108. data/lib/sequel/extensions/named_timezones.rb +26 -6
  109. data/lib/sequel/extensions/pagination.rb +1 -1
  110. data/lib/sequel/extensions/pg_array.rb +23 -3
  111. data/lib/sequel/extensions/pg_array_ops.rb +2 -2
  112. data/lib/sequel/extensions/pg_auto_parameterize.rb +478 -0
  113. data/lib/sequel/extensions/pg_enum.rb +1 -1
  114. data/lib/sequel/extensions/pg_extended_date_support.rb +28 -25
  115. data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
  116. data/lib/sequel/extensions/pg_hstore.rb +6 -1
  117. data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
  118. data/lib/sequel/extensions/pg_inet.rb +10 -11
  119. data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
  120. data/lib/sequel/extensions/pg_interval.rb +45 -19
  121. data/lib/sequel/extensions/pg_json.rb +13 -15
  122. data/lib/sequel/extensions/pg_json_ops.rb +73 -2
  123. data/lib/sequel/extensions/pg_loose_count.rb +3 -1
  124. data/lib/sequel/extensions/pg_multirange.rb +367 -0
  125. data/lib/sequel/extensions/pg_range.rb +10 -23
  126. data/lib/sequel/extensions/pg_range_ops.rb +37 -9
  127. data/lib/sequel/extensions/pg_row.rb +19 -13
  128. data/lib/sequel/extensions/pg_row_ops.rb +1 -1
  129. data/lib/sequel/extensions/query.rb +2 -0
  130. data/lib/sequel/extensions/s.rb +2 -1
  131. data/lib/sequel/extensions/schema_dumper.rb +13 -2
  132. data/lib/sequel/extensions/server_block.rb +8 -12
  133. data/lib/sequel/extensions/sql_comments.rb +110 -3
  134. data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
  135. data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
  136. data/lib/sequel/extensions/string_agg.rb +1 -1
  137. data/lib/sequel/extensions/string_date_time.rb +19 -23
  138. data/lib/sequel/extensions/symbol_aref.rb +2 -0
  139. data/lib/sequel/model/associations.rb +325 -96
  140. data/lib/sequel/model/base.rb +51 -27
  141. data/lib/sequel/model/errors.rb +10 -1
  142. data/lib/sequel/model/inflections.rb +1 -1
  143. data/lib/sequel/model/plugins.rb +5 -0
  144. data/lib/sequel/plugins/association_proxies.rb +2 -0
  145. data/lib/sequel/plugins/async_thread_pool.rb +39 -0
  146. data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
  147. data/lib/sequel/plugins/auto_validations.rb +87 -15
  148. data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
  149. data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
  150. data/lib/sequel/plugins/column_encryption.rb +728 -0
  151. data/lib/sequel/plugins/composition.rb +10 -4
  152. data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
  153. data/lib/sequel/plugins/constraint_validations.rb +2 -1
  154. data/lib/sequel/plugins/dataset_associations.rb +4 -1
  155. data/lib/sequel/plugins/dirty.rb +1 -1
  156. data/lib/sequel/plugins/enum.rb +124 -0
  157. data/lib/sequel/plugins/finder.rb +3 -1
  158. data/lib/sequel/plugins/insert_conflict.rb +4 -0
  159. data/lib/sequel/plugins/instance_specific_default.rb +1 -1
  160. data/lib/sequel/plugins/json_serializer.rb +39 -24
  161. data/lib/sequel/plugins/lazy_attributes.rb +3 -0
  162. data/lib/sequel/plugins/list.rb +3 -1
  163. data/lib/sequel/plugins/many_through_many.rb +108 -9
  164. data/lib/sequel/plugins/nested_attributes.rb +12 -7
  165. data/lib/sequel/plugins/pg_array_associations.rb +56 -38
  166. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +3 -1
  167. data/lib/sequel/plugins/prepared_statements.rb +10 -1
  168. data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
  169. data/lib/sequel/plugins/rcte_tree.rb +27 -19
  170. data/lib/sequel/plugins/require_valid_schema.rb +67 -0
  171. data/lib/sequel/plugins/serialization.rb +9 -3
  172. data/lib/sequel/plugins/serialization_modification_detection.rb +2 -1
  173. data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
  174. data/lib/sequel/plugins/sql_comments.rb +189 -0
  175. data/lib/sequel/plugins/static_cache.rb +1 -1
  176. data/lib/sequel/plugins/subclasses.rb +28 -11
  177. data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
  178. data/lib/sequel/plugins/timestamps.rb +1 -1
  179. data/lib/sequel/plugins/unused_associations.rb +521 -0
  180. data/lib/sequel/plugins/update_or_create.rb +1 -1
  181. data/lib/sequel/plugins/validate_associated.rb +22 -12
  182. data/lib/sequel/plugins/validation_helpers.rb +38 -11
  183. data/lib/sequel/plugins/xml_serializer.rb +1 -1
  184. data/lib/sequel/sql.rb +1 -1
  185. data/lib/sequel/timezones.rb +12 -14
  186. data/lib/sequel/version.rb +1 -1
  187. metadata +97 -43
@@ -175,6 +175,9 @@ module Sequel
175
175
  if !c[:max_length] && c[:type] == :string && (max_length = column_schema_max_length(c[:db_type]))
176
176
  c[:max_length] = max_length
177
177
  end
178
+ if !c[:max_value] && !c[:min_value] && c[:type] == :integer && (min_max = column_schema_integer_min_max_values(c[:db_type]))
179
+ c[:min_value], c[:max_value] = min_max
180
+ end
178
181
  end
179
182
  schema_post_process(cols)
180
183
 
@@ -236,7 +239,7 @@ module Sequel
236
239
  when :date
237
240
  Sequel.string_to_date(default)
238
241
  when :datetime
239
- DateTime.parse(default)
242
+ Sequel.string_to_datetime(default)
240
243
  when :time
241
244
  Sequel.string_to_time(default)
242
245
  when :decimal
@@ -272,6 +275,40 @@ module Sequel
272
275
  column_schema_default_to_ruby_value(default, type) rescue nil
273
276
  end
274
277
 
278
+ INTEGER1_MIN_MAX = [-128, 127].freeze
279
+ INTEGER2_MIN_MAX = [-32768, 32767].freeze
280
+ INTEGER3_MIN_MAX = [-8388608, 8388607].freeze
281
+ INTEGER4_MIN_MAX = [-2147483648, 2147483647].freeze
282
+ INTEGER8_MIN_MAX = [-9223372036854775808, 9223372036854775807].freeze
283
+ UNSIGNED_INTEGER1_MIN_MAX = [0, 255].freeze
284
+ UNSIGNED_INTEGER2_MIN_MAX = [0, 65535].freeze
285
+ UNSIGNED_INTEGER3_MIN_MAX = [0, 16777215].freeze
286
+ UNSIGNED_INTEGER4_MIN_MAX = [0, 4294967295].freeze
287
+ UNSIGNED_INTEGER8_MIN_MAX = [0, 18446744073709551615].freeze
288
+
289
+ # Look at the db_type and guess the minimum and maximum integer values for
290
+ # the column.
291
+ def column_schema_integer_min_max_values(db_type)
292
+ unsigned = /unsigned/i =~ db_type
293
+ case db_type
294
+ when /big|int8/i
295
+ unsigned ? UNSIGNED_INTEGER8_MIN_MAX : INTEGER8_MIN_MAX
296
+ when /medium/i
297
+ unsigned ? UNSIGNED_INTEGER3_MIN_MAX : INTEGER3_MIN_MAX
298
+ when /small|int2/i
299
+ unsigned ? UNSIGNED_INTEGER2_MIN_MAX : INTEGER2_MIN_MAX
300
+ when /tiny/i
301
+ (unsigned || column_schema_tinyint_type_is_unsigned?) ? UNSIGNED_INTEGER1_MIN_MAX : INTEGER1_MIN_MAX
302
+ else
303
+ unsigned ? UNSIGNED_INTEGER4_MIN_MAX : INTEGER4_MIN_MAX
304
+ end
305
+ end
306
+
307
+ # Whether the tinyint type (if supported by the database) is unsigned by default.
308
+ def column_schema_tinyint_type_is_unsigned?
309
+ false
310
+ end
311
+
275
312
  # Look at the db_type and guess the maximum length of the column.
276
313
  # This assumes types such as varchar(255).
277
314
  def column_schema_max_length(db_type)
@@ -146,6 +146,9 @@ module Sequel
146
146
  #
147
147
  # :generated_type :: Set the type of column when using :generated_always_as,
148
148
  # should be :virtual or :stored to force a type.
149
+ # :on_update_current_timestamp :: Use ON UPDATE CURRENT TIMESTAMP when defining the column,
150
+ # which will update the column value to CURRENT_TIMESTAMP
151
+ # on every UPDATE.
149
152
  #
150
153
  # Microsoft SQL Server specific options:
151
154
  #
@@ -159,7 +162,7 @@ module Sequel
159
162
  nil
160
163
  end
161
164
 
162
- # Adds a named constraint (or unnamed if name is nil),
165
+ # Adds a named CHECK constraint (or unnamed if name is nil),
163
166
  # with the given block or args. To provide options for the constraint, pass
164
167
  # a hash as the first argument.
165
168
  #
@@ -167,6 +170,15 @@ module Sequel
167
170
  # # CONSTRAINT blah CHECK num >= 1 AND num <= 5
168
171
  # constraint({name: :blah, deferrable: true}, num: 1..5)
169
172
  # # CONSTRAINT blah CHECK num >= 1 AND num <= 5 DEFERRABLE INITIALLY DEFERRED
173
+ #
174
+ # If the first argument is a hash, the following options are supported:
175
+ #
176
+ # Options:
177
+ # :name :: The name of the CHECK constraint
178
+ # :deferrable :: Whether the CHECK constraint should be marked DEFERRABLE.
179
+ #
180
+ # PostgreSQL specific options:
181
+ # :not_valid :: Whether the CHECK constraint should be marked NOT VALID.
170
182
  def constraint(name, *args, &block)
171
183
  opts = name.is_a?(Hash) ? name : {:name=>name}
172
184
  constraints << opts.merge(:type=>:check, :check=>block || args)
@@ -205,14 +217,12 @@ module Sequel
205
217
  end
206
218
 
207
219
  # Add a full text index on the given columns.
220
+ # See #index for additional options.
208
221
  #
209
222
  # PostgreSQL specific options:
210
223
  # :index_type :: Can be set to :gist to use a GIST index instead of the
211
224
  # default GIN index.
212
225
  # :language :: Set a language to use for the index (default: simple).
213
- #
214
- # Microsoft SQL Server specific options:
215
- # :key_index :: The KEY INDEX to use for the full text index.
216
226
  def full_text_index(columns, opts = OPTS)
217
227
  index(columns, opts.merge(:type => :full_text))
218
228
  end
@@ -222,35 +232,44 @@ module Sequel
222
232
  columns.any?{|c| c[:name] == name}
223
233
  end
224
234
 
225
- # Add an index on the given column(s) with the given options.
235
+ # Add an index on the given column(s) with the given options. Examples:
236
+ #
237
+ # index :name
238
+ # # CREATE INDEX table_name_index ON table (name)
239
+ #
240
+ # index [:artist_id, :name]
241
+ # # CREATE INDEX table_artist_id_name_index ON table (artist_id, name)
242
+ #
243
+ # index [:artist_id, :name], name: :foo
244
+ # # CREATE INDEX foo ON table (artist_id, name)
245
+ #
226
246
  # General options:
227
247
  #
248
+ # :include :: Include additional column values in the index, without
249
+ # actually indexing on those values (only supported by
250
+ # some databases).
228
251
  # :name :: The name to use for the index. If not given, a default name
229
252
  # based on the table and columns is used.
230
- # :type :: The type of index to use (only supported by some databases)
253
+ # :type :: The type of index to use (only supported by some databases,
254
+ # :full_text and :spatial values are handled specially).
231
255
  # :unique :: Make the index unique, so duplicate values are not allowed.
232
- # :where :: Create a partial index (only supported by some databases)
256
+ # :where :: A filter expression, used to create a partial index (only
257
+ # supported by some databases).
233
258
  #
234
259
  # PostgreSQL specific options:
235
260
  #
236
261
  # :concurrently :: Create the index concurrently, so it doesn't block
237
262
  # operations on the table while the index is being
238
263
  # built.
239
- # :opclass :: Use a specific operator class in the index.
240
- # :include :: Include additional column values in the index, without
241
- # actually indexing on those values (PostgreSQL 11+).
264
+ # :if_not_exists :: Only create the index if an index of the same name doesn't already exist.
265
+ # :nulls_distinct :: Set whether separate NULLs should be considered distinct values in unique indexes.
266
+ # :opclass :: Set an opclass to use for all columns (per-column opclasses require
267
+ # custom SQL).
242
268
  # :tablespace :: Specify tablespace for index.
243
269
  #
244
270
  # Microsoft SQL Server specific options:
245
271
  #
246
- # :include :: Include additional column values in the index, without
247
- # actually indexing on those values.
248
- #
249
- # index :name
250
- # # CREATE INDEX table_name_index ON table (name)
251
- #
252
- # index [:artist_id, :name]
253
- # # CREATE INDEX table_artist_id_name_index ON table (artist_id, name)
272
+ # :key_index :: Sets the KEY INDEX to the given value.
254
273
  def index(columns, opts = OPTS)
255
274
  indexes << {:columns => Array(columns)}.merge!(opts)
256
275
  nil
@@ -316,6 +335,7 @@ module Sequel
316
335
  end
317
336
 
318
337
  # Add a spatial index on the given columns.
338
+ # See #index for additional options.
319
339
  def spatial_index(columns, opts = OPTS)
320
340
  index(columns, opts.merge(:type => :spatial))
321
341
  end
@@ -371,8 +391,7 @@ module Sequel
371
391
  end
372
392
 
373
393
  # Add a column with the given name, type, and opts.
374
- # See CreateTableGenerator#column for the available options (except for +:index+, use a
375
- # separate +add_index+ call to add an index for the column).
394
+ # See CreateTableGenerator#column for the available options.
376
395
  #
377
396
  # add_column(:name, String) # ADD COLUMN name varchar(255)
378
397
  #
@@ -385,7 +404,10 @@ module Sequel
385
404
  # :after :: The name of an existing column that the new column should be positioned after
386
405
  # :first :: Create this new column before all other existing columns
387
406
  def add_column(name, type, opts = OPTS)
388
- @operations << {:op => :add_column, :name => name, :type => type}.merge!(opts)
407
+ op = {:op => :add_column, :name => name, :type => type}.merge!(opts)
408
+ index_opts = op.delete(:index)
409
+ @operations << op
410
+ add_index(name, index_opts.is_a?(Hash) ? index_opts : OPTS) if index_opts
389
411
  nil
390
412
  end
391
413
 
@@ -414,8 +436,7 @@ module Sequel
414
436
  end
415
437
 
416
438
  # Add a foreign key with the given name and referencing the given table.
417
- # See CreateTableGenerator#column for the available options (except for +:index+, use a
418
- # separate +add_index+ call to add an index for the column).
439
+ # See CreateTableGenerator#column for the available options.
419
440
  #
420
441
  # You can also pass an array of column names for creating composite foreign
421
442
  # keys. In this case, it will assume the columns exist and will only add
@@ -442,7 +463,7 @@ module Sequel
442
463
  end
443
464
 
444
465
  # Add a full text index on the given columns.
445
- # See CreateTableGenerator#index for available options.
466
+ # See CreateTableGenerator#full_text_index for available options.
446
467
  def add_full_text_index(columns, opts = OPTS)
447
468
  add_index(columns, {:type=>:full_text}.merge!(opts))
448
469
  end
@@ -451,34 +472,6 @@ module Sequel
451
472
  # CreateTableGenerator#index for available options.
452
473
  #
453
474
  # add_index(:artist_id) # CREATE INDEX table_artist_id_index ON table (artist_id)
454
- #
455
- # Options:
456
- #
457
- # :name :: Give a specific name for the index. Highly recommended if you plan on
458
- # dropping the index later.
459
- # :where :: A filter expression, used to setup a partial index (if supported).
460
- # :unique :: Create a unique index.
461
- #
462
- # PostgreSQL specific options:
463
- #
464
- # :concurrently :: Create the index concurrently, so it doesn't require an exclusive lock
465
- # on the table.
466
- # :index_type :: The underlying index type to use for a full_text index, gin by default).
467
- # :language :: The language to use for a full text index (simple by default).
468
- # :opclass :: Set an opclass to use for all columns (per-column opclasses require
469
- # custom SQL).
470
- # :type :: Set the index type (e.g. full_text, spatial, hash, gin, gist, btree).
471
- # :if_not_exists :: Only create the index if an index of the same name doesn't already exists
472
- #
473
- # MySQL specific options:
474
- #
475
- # :type :: Set the index type, with full_text and spatial indexes handled specially.
476
- #
477
- # Microsoft SQL Server specific options:
478
- #
479
- # :include :: Includes additional columns in the index.
480
- # :key_index :: Sets the KEY INDEX to the given value.
481
- # :type :: clustered uses a clustered index, full_text uses a full text index.
482
475
  def add_index(columns, opts = OPTS)
483
476
  @operations << {:op => :add_index, :columns => Array(columns)}.merge!(opts)
484
477
  nil
@@ -63,7 +63,7 @@ module Sequel
63
63
  # definitions using <tt>create_table</tt>, and +add_index+ accepts all the options
64
64
  # available for index definition.
65
65
  #
66
- # See <tt>Schema::AlterTableGenerator</tt> and the {"Migrations and Schema Modification" guide}[rdoc-ref:doc/migration.rdoc].
66
+ # See <tt>Schema::AlterTableGenerator</tt> and the {Migrations guide}[rdoc-ref:doc/migration.rdoc].
67
67
  def alter_table(name, &block)
68
68
  generator = alter_table_generator(&block)
69
69
  remove_cached_schema(name)
@@ -183,6 +183,15 @@ module Sequel
183
183
  # keys.
184
184
  # :tablespace :: The tablespace to use for the table.
185
185
  #
186
+ # SQLite specific options:
187
+ # :strict :: Create a STRICT table, which checks that the values for the columns
188
+ # are the correct type (similar to all other SQL databases). Note that
189
+ # when using this option, all column types used should be one of the
190
+ # following: +int+, +integer+, +real+, +text+, +blob+, and +any+.
191
+ # The +any+ type is treated like a SQLite column in a non-strict table,
192
+ # allowing any type of data to be stored. This option is supported on
193
+ # SQLite 3.37.0+.
194
+ #
186
195
  # See <tt>Schema::CreateTableGenerator</tt> and the {"Schema Modification" guide}[rdoc-ref:doc/schema_modification.rdoc].
187
196
  def create_table(name, options=OPTS, &block)
188
197
  remove_cached_schema(name)
@@ -262,6 +271,10 @@ module Sequel
262
271
  # # SELECT * FROM items WHERE foo
263
272
  # # WITH CHECK OPTION
264
273
  #
274
+ # DB.create_view(:bar_items, DB[:items].select(:foo), columns: [:bar])
275
+ # # CREATE VIEW bar_items (bar) AS
276
+ # # SELECT foo FROM items
277
+ #
265
278
  # Options:
266
279
  # :columns :: The column names to use for the view. If not given,
267
280
  # automatically determined based on the input dataset.
@@ -282,6 +295,9 @@ module Sequel
282
295
  # in a subquery, if you are providing a Dataset as the source
283
296
  # argument, if should probably call the union method with the
284
297
  # all: true and from_self: false options.
298
+ # :security_invoker :: Set the security_invoker property on the view, making
299
+ # the access to the view use the current user's permissions,
300
+ # instead of the view owner's permissions.
285
301
  # :tablespace :: The tablespace to use for materialized views.
286
302
  def create_view(name, source, options = OPTS)
287
303
  execute_ddl(create_view_sql(name, source, options))
@@ -19,7 +19,7 @@ module Sequel
19
19
  METHS
20
20
 
21
21
  # The clone options to use when retrieving columns for a dataset.
22
- COLUMNS_CLONE_OPTIONS = {:distinct => nil, :limit => 1, :offset=>nil, :where=>nil, :having=>nil, :order=>nil, :row_proc=>nil, :graph=>nil, :eager_graph=>nil}.freeze
22
+ COLUMNS_CLONE_OPTIONS = {:distinct => nil, :limit => 0, :offset=>nil, :where=>nil, :having=>nil, :order=>nil, :row_proc=>nil, :graph=>nil, :eager_graph=>nil}.freeze
23
23
 
24
24
  # Inserts the given argument into the database. Returns self so it
25
25
  # can be used safely when chaining:
@@ -127,6 +127,18 @@ module Sequel
127
127
  #
128
128
  # DB[:table].delete # DELETE * FROM table
129
129
  # # => 3
130
+ #
131
+ # Some databases support using multiple tables in a DELETE query. This requires
132
+ # multiple FROM tables (JOINs can also be used). As multiple FROM tables use
133
+ # an implicit CROSS JOIN, you should make sure your WHERE condition uses the
134
+ # appropriate filters for the FROM tables:
135
+ #
136
+ # DB.from(:a, :b).join(:c, :d=>Sequel[:b][:e]).where{{a[:f]=>b[:g], a[:id]=>c[:h]}}.
137
+ # delete
138
+ # # DELETE FROM a
139
+ # # USING b
140
+ # # INNER JOIN c ON (c.d = b.e)
141
+ # # WHERE ((a.f = b.g) AND (a.id = c.h))
130
142
  def delete(&block)
131
143
  sql = delete_sql
132
144
  if uses_returning?(:delete)
@@ -313,14 +325,18 @@ module Sequel
313
325
 
314
326
  # Inserts multiple records into the associated table. This method can be
315
327
  # used to efficiently insert a large number of records into a table in a
316
- # single query if the database supports it. Inserts
317
- # are automatically wrapped in a transaction.
328
+ # single query if the database supports it. Inserts are automatically
329
+ # wrapped in a transaction if necessary.
318
330
  #
319
331
  # This method is called with a columns array and an array of value arrays:
320
332
  #
321
333
  # DB[:table].import([:x, :y], [[1, 2], [3, 4]])
322
334
  # # INSERT INTO table (x, y) VALUES (1, 2)
323
- # # INSERT INTO table (x, y) VALUES (3, 4)
335
+ # # INSERT INTO table (x, y) VALUES (3, 4)
336
+ #
337
+ # or, if the database supports it:
338
+ #
339
+ # # INSERT INTO table (x, y) VALUES (1, 2), (3, 4)
324
340
  #
325
341
  # This method also accepts a dataset instead of an array of value arrays:
326
342
  #
@@ -328,9 +344,13 @@ module Sequel
328
344
  # # INSERT INTO table (x, y) SELECT a, b FROM table2
329
345
  #
330
346
  # Options:
331
- # :commit_every :: Open a new transaction for every given number of records.
332
- # For example, if you provide a value of 50, will commit
333
- # after every 50 records.
347
+ # :commit_every :: Open a new transaction for every given number of
348
+ # records. For example, if you provide a value of 50,
349
+ # will commit after every 50 records. When a
350
+ # transaction is not required, this option controls
351
+ # the maximum number of values to insert with a single
352
+ # statement; it does not force the use of a
353
+ # transaction.
334
354
  # :return :: When this is set to :primary_key, returns an array of
335
355
  # autoincremented primary key values for the rows inserted.
336
356
  # This does not have an effect if +values+ is a Dataset.
@@ -457,6 +477,55 @@ module Sequel
457
477
  _aggregate(:max, arg)
458
478
  end
459
479
 
480
+ # Execute a MERGE statement, which allows for INSERT, UPDATE, and DELETE
481
+ # behavior in a single query, based on whether rows from a source table
482
+ # match rows in the current table, based on the join conditions.
483
+ #
484
+ # Unless the dataset uses static SQL, to use #merge, you must first have
485
+ # called #merge_using to specify the merge source and join conditions.
486
+ # You will then likely to call one or more of the following methods
487
+ # to specify MERGE behavior by adding WHEN [NOT] MATCHED clauses:
488
+ #
489
+ # * #merge_insert
490
+ # * #merge_update
491
+ # * #merge_delete
492
+ #
493
+ # The WHEN [NOT] MATCHED clauses are added to the SQL in the order these
494
+ # methods were called on the dataset. If none of these methods are
495
+ # called, an error is raised.
496
+ #
497
+ # Example:
498
+ #
499
+ # DB[:m1]
500
+ # merge_using(:m2, i1: :i2).
501
+ # merge_insert(i1: :i2, a: Sequel[:b]+11).
502
+ # merge_delete{a > 30}.
503
+ # merge_update(i1: Sequel[:i1]+:i2+10, a: Sequel[:a]+:b+20).
504
+ # merge
505
+ #
506
+ # SQL:
507
+ #
508
+ # MERGE INTO m1 USING m2 ON (i1 = i2)
509
+ # WHEN NOT MATCHED THEN INSERT (i1, a) VALUES (i2, (b + 11))
510
+ # WHEN MATCHED AND (a > 30) THEN DELETE
511
+ # WHEN MATCHED THEN UPDATE SET i1 = (i1 + i2 + 10), a = (a + b + 20)
512
+ #
513
+ # On PostgreSQL, two additional merge methods are supported, for the
514
+ # PostgreSQL-specific DO NOTHING syntax.
515
+ #
516
+ # * #merge_do_nothing_when_matched
517
+ # * #merge_do_nothing_when_not_matched
518
+ #
519
+ # This method is supported on Oracle, but Oracle's MERGE support is
520
+ # non-standard, and has the following issues:
521
+ #
522
+ # * DELETE clause requires UPDATE clause
523
+ # * DELETE clause requires a condition
524
+ # * DELETE clause only affects rows updated by UPDATE clause
525
+ def merge
526
+ execute_ddl(merge_sql)
527
+ end
528
+
460
529
  # Returns the minimum value for the given column/expression.
461
530
  # Uses a virtual row block if no argument is given.
462
531
  #
@@ -527,7 +596,7 @@ module Sequel
527
596
  # # SELECT * FROM table ORDER BY id LIMIT 1000 OFFSET 1000
528
597
  # # ...
529
598
  #
530
- # DB[:table].order(:id).paged_each(:rows_per_fetch=>100){|row| }
599
+ # DB[:table].order(:id).paged_each(rows_per_fetch: 100){|row| }
531
600
  # # SELECT * FROM table ORDER BY id LIMIT 100
532
601
  # # SELECT * FROM table ORDER BY id LIMIT 100 OFFSET 100
533
602
  # # ...
@@ -546,7 +615,7 @@ module Sequel
546
615
  unless @opts[:order]
547
616
  raise Sequel::Error, "Dataset#paged_each requires the dataset be ordered"
548
617
  end
549
- unless block_given?
618
+ unless defined?(yield)
550
619
  return enum_for(:paged_each, opts)
551
620
  end
552
621
 
@@ -869,6 +938,19 @@ module Sequel
869
938
  #
870
939
  # DB[:table].update(x: Sequel[:x]+1, y: 0) # UPDATE table SET x = (x + 1), y = 0
871
940
  # # => 10
941
+ #
942
+ # Some databases support using multiple tables in an UPDATE query. This requires
943
+ # multiple FROM tables (JOINs can also be used). As multiple FROM tables use
944
+ # an implicit CROSS JOIN, you should make sure your WHERE condition uses the
945
+ # appropriate filters for the FROM tables:
946
+ #
947
+ # DB.from(:a, :b).join(:c, :d=>Sequel[:b][:e]).where{{a[:f]=>b[:g], a[:id]=>10}}.
948
+ # update(:f=>Sequel[:c][:h])
949
+ # # UPDATE a
950
+ # # SET f = c.h
951
+ # # FROM b
952
+ # # INNER JOIN c ON (c.d = b.e)
953
+ # # WHERE ((a.f = b.g) AND (a.id = 10))
872
954
  def update(values=OPTS, &block)
873
955
  sql = update_sql(values)
874
956
  if uses_returning?(:update)
@@ -974,18 +1056,19 @@ module Sequel
974
1056
 
975
1057
  # Internals of #import. If primary key values are requested, use
976
1058
  # separate insert commands for each row. Otherwise, call #multi_insert_sql
977
- # and execute each statement it gives separately.
1059
+ # and execute each statement it gives separately. A transaction is only used
1060
+ # if there are multiple statements to execute.
978
1061
  def _import(columns, values, opts)
979
1062
  trans_opts = Hash[opts]
980
1063
  trans_opts[:server] = @opts[:server]
981
1064
  if opts[:return] == :primary_key
982
- @db.transaction(trans_opts){values.map{|v| insert(columns, v)}}
1065
+ _import_transaction(values, trans_opts){values.map{|v| insert(columns, v)}}
983
1066
  else
984
1067
  stmts = multi_insert_sql(columns, values)
985
- @db.transaction(trans_opts){stmts.each{|st| execute_dui(st)}}
1068
+ _import_transaction(stmts, trans_opts){stmts.each{|st| execute_dui(st)}}
986
1069
  end
987
1070
  end
988
-
1071
+
989
1072
  # Return an array of arrays of values given by the symbols in ret_cols.
990
1073
  def _select_map_multiple(ret_cols)
991
1074
  map{|r| r.values_at(*ret_cols)}
@@ -1024,6 +1107,17 @@ module Sequel
1024
1107
  end
1025
1108
  end
1026
1109
 
1110
+ # Use a transaction when yielding to the block if multiple values/statements
1111
+ # are provided. When only a single value or statement is provided, then yield
1112
+ # without using a transaction.
1113
+ def _import_transaction(values, trans_opts, &block)
1114
+ if values.length > 1
1115
+ @db.transaction(trans_opts, &block)
1116
+ else
1117
+ yield
1118
+ end
1119
+ end
1120
+
1027
1121
  # Internals of +select_hash+ and +select_hash_groups+
1028
1122
  def _select_hash(meth, key_column, value_column, opts=OPTS)
1029
1123
  select(*(key_column.is_a?(Array) ? key_column : [key_column]) + (value_column.is_a?(Array) ? value_column : [value_column])).
@@ -51,6 +51,11 @@ module Sequel
51
51
  false
52
52
  end
53
53
 
54
+ # Whether deleting from joined datasets is supported, false by default.
55
+ def supports_deleting_joins?
56
+ supports_modifying_joins?
57
+ end
58
+
54
59
  # Whether the database supports derived column lists (e.g.
55
60
  # "table_expr AS table_alias(column_alias1, column_alias2, ...)"), true by
56
61
  # default.
@@ -120,6 +125,11 @@ module Sequel
120
125
  false
121
126
  end
122
127
 
128
+ # Whether the MERGE statement is supported, false by default.
129
+ def supports_merge?
130
+ false
131
+ end
132
+
123
133
  # Whether modifying joined datasets is supported, false by default.
124
134
  def supports_modifying_joins?
125
135
  false
@@ -142,6 +152,11 @@ module Sequel
142
152
  supports_distinct_on?
143
153
  end
144
154
 
155
+ # Whether placeholder literalizers are supported, true by default.
156
+ def supports_placeholder_literalizer?
157
+ true
158
+ end
159
+
145
160
  # Whether the dataset supports pattern matching by regular expressions, false by default.
146
161
  def supports_regexp?
147
162
  false
@@ -178,6 +193,11 @@ module Sequel
178
193
  true
179
194
  end
180
195
 
196
+ # Whether updating joined datasets is supported, false by default.
197
+ def supports_updating_joins?
198
+ supports_modifying_joins?
199
+ end
200
+
181
201
  # Whether the dataset supports the WINDOW clause to define windows used by multiple
182
202
  # window functions, false by default.
183
203
  def supports_window_clause?
@@ -302,7 +302,7 @@ module Sequel
302
302
  cache_set(key, loader + 1)
303
303
  loader = nil
304
304
  end
305
- elsif cache_sql?
305
+ elsif cache_sql? && supports_placeholder_literalizer?
306
306
  cache_set(key, 1)
307
307
  end
308
308
 
@@ -201,7 +201,9 @@ module Sequel
201
201
  when :insert_pk
202
202
  fetch_rows(prepared_sql){|r| return r.values.first}
203
203
  when Array
204
+ # :nocov:
204
205
  case prepared_type[0]
206
+ # :nocov:
205
207
  when :map, :as_hash, :to_hash, :to_hash_groups
206
208
  public_send(*prepared_type, &block)
207
209
  end