sequel 5.82.0 → 5.84.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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sequel +9 -17
  3. data/lib/sequel/adapters/jdbc/derby.rb +1 -1
  4. data/lib/sequel/adapters/shared/db2.rb +1 -1
  5. data/lib/sequel/adapters/shared/mssql.rb +14 -2
  6. data/lib/sequel/adapters/shared/postgres.rb +42 -4
  7. data/lib/sequel/adapters/shared/sqlite.rb +3 -1
  8. data/lib/sequel/database/connecting.rb +1 -4
  9. data/lib/sequel/database/misc.rb +27 -7
  10. data/lib/sequel/database/schema_methods.rb +17 -1
  11. data/lib/sequel/dataset/sql.rb +13 -0
  12. data/lib/sequel/extensions/pg_json_ops.rb +328 -1
  13. data/lib/sequel/extensions/stdio_logger.rb +48 -0
  14. data/lib/sequel/extensions/string_agg.rb +15 -2
  15. data/lib/sequel/plugins/defaults_setter.rb +16 -4
  16. data/lib/sequel/plugins/optimistic_locking.rb +2 -0
  17. data/lib/sequel/sql.rb +8 -5
  18. data/lib/sequel/version.rb +1 -1
  19. metadata +4 -235
  20. data/CHANGELOG +0 -1377
  21. data/README.rdoc +0 -936
  22. data/doc/advanced_associations.rdoc +0 -884
  23. data/doc/association_basics.rdoc +0 -1859
  24. data/doc/bin_sequel.rdoc +0 -146
  25. data/doc/cheat_sheet.rdoc +0 -255
  26. data/doc/code_order.rdoc +0 -104
  27. data/doc/core_extensions.rdoc +0 -405
  28. data/doc/dataset_basics.rdoc +0 -96
  29. data/doc/dataset_filtering.rdoc +0 -222
  30. data/doc/extensions.rdoc +0 -77
  31. data/doc/fork_safety.rdoc +0 -84
  32. data/doc/mass_assignment.rdoc +0 -98
  33. data/doc/migration.rdoc +0 -660
  34. data/doc/model_dataset_method_design.rdoc +0 -129
  35. data/doc/model_hooks.rdoc +0 -254
  36. data/doc/model_plugins.rdoc +0 -270
  37. data/doc/mssql_stored_procedures.rdoc +0 -43
  38. data/doc/object_model.rdoc +0 -563
  39. data/doc/opening_databases.rdoc +0 -439
  40. data/doc/postgresql.rdoc +0 -611
  41. data/doc/prepared_statements.rdoc +0 -144
  42. data/doc/querying.rdoc +0 -1070
  43. data/doc/reflection.rdoc +0 -120
  44. data/doc/release_notes/5.0.0.txt +0 -159
  45. data/doc/release_notes/5.1.0.txt +0 -31
  46. data/doc/release_notes/5.10.0.txt +0 -84
  47. data/doc/release_notes/5.11.0.txt +0 -83
  48. data/doc/release_notes/5.12.0.txt +0 -141
  49. data/doc/release_notes/5.13.0.txt +0 -27
  50. data/doc/release_notes/5.14.0.txt +0 -63
  51. data/doc/release_notes/5.15.0.txt +0 -39
  52. data/doc/release_notes/5.16.0.txt +0 -110
  53. data/doc/release_notes/5.17.0.txt +0 -31
  54. data/doc/release_notes/5.18.0.txt +0 -69
  55. data/doc/release_notes/5.19.0.txt +0 -28
  56. data/doc/release_notes/5.2.0.txt +0 -33
  57. data/doc/release_notes/5.20.0.txt +0 -89
  58. data/doc/release_notes/5.21.0.txt +0 -87
  59. data/doc/release_notes/5.22.0.txt +0 -48
  60. data/doc/release_notes/5.23.0.txt +0 -56
  61. data/doc/release_notes/5.24.0.txt +0 -56
  62. data/doc/release_notes/5.25.0.txt +0 -32
  63. data/doc/release_notes/5.26.0.txt +0 -35
  64. data/doc/release_notes/5.27.0.txt +0 -21
  65. data/doc/release_notes/5.28.0.txt +0 -16
  66. data/doc/release_notes/5.29.0.txt +0 -22
  67. data/doc/release_notes/5.3.0.txt +0 -121
  68. data/doc/release_notes/5.30.0.txt +0 -20
  69. data/doc/release_notes/5.31.0.txt +0 -148
  70. data/doc/release_notes/5.32.0.txt +0 -46
  71. data/doc/release_notes/5.33.0.txt +0 -24
  72. data/doc/release_notes/5.34.0.txt +0 -40
  73. data/doc/release_notes/5.35.0.txt +0 -56
  74. data/doc/release_notes/5.36.0.txt +0 -60
  75. data/doc/release_notes/5.37.0.txt +0 -30
  76. data/doc/release_notes/5.38.0.txt +0 -28
  77. data/doc/release_notes/5.39.0.txt +0 -19
  78. data/doc/release_notes/5.4.0.txt +0 -80
  79. data/doc/release_notes/5.40.0.txt +0 -40
  80. data/doc/release_notes/5.41.0.txt +0 -25
  81. data/doc/release_notes/5.42.0.txt +0 -136
  82. data/doc/release_notes/5.43.0.txt +0 -98
  83. data/doc/release_notes/5.44.0.txt +0 -32
  84. data/doc/release_notes/5.45.0.txt +0 -34
  85. data/doc/release_notes/5.46.0.txt +0 -87
  86. data/doc/release_notes/5.47.0.txt +0 -59
  87. data/doc/release_notes/5.48.0.txt +0 -14
  88. data/doc/release_notes/5.49.0.txt +0 -59
  89. data/doc/release_notes/5.5.0.txt +0 -61
  90. data/doc/release_notes/5.50.0.txt +0 -78
  91. data/doc/release_notes/5.51.0.txt +0 -47
  92. data/doc/release_notes/5.52.0.txt +0 -87
  93. data/doc/release_notes/5.53.0.txt +0 -23
  94. data/doc/release_notes/5.54.0.txt +0 -27
  95. data/doc/release_notes/5.55.0.txt +0 -21
  96. data/doc/release_notes/5.56.0.txt +0 -51
  97. data/doc/release_notes/5.57.0.txt +0 -23
  98. data/doc/release_notes/5.58.0.txt +0 -31
  99. data/doc/release_notes/5.59.0.txt +0 -73
  100. data/doc/release_notes/5.6.0.txt +0 -31
  101. data/doc/release_notes/5.60.0.txt +0 -22
  102. data/doc/release_notes/5.61.0.txt +0 -43
  103. data/doc/release_notes/5.62.0.txt +0 -132
  104. data/doc/release_notes/5.63.0.txt +0 -33
  105. data/doc/release_notes/5.64.0.txt +0 -50
  106. data/doc/release_notes/5.65.0.txt +0 -21
  107. data/doc/release_notes/5.66.0.txt +0 -24
  108. data/doc/release_notes/5.67.0.txt +0 -32
  109. data/doc/release_notes/5.68.0.txt +0 -61
  110. data/doc/release_notes/5.69.0.txt +0 -26
  111. data/doc/release_notes/5.7.0.txt +0 -108
  112. data/doc/release_notes/5.70.0.txt +0 -35
  113. data/doc/release_notes/5.71.0.txt +0 -21
  114. data/doc/release_notes/5.72.0.txt +0 -33
  115. data/doc/release_notes/5.73.0.txt +0 -66
  116. data/doc/release_notes/5.74.0.txt +0 -45
  117. data/doc/release_notes/5.75.0.txt +0 -35
  118. data/doc/release_notes/5.76.0.txt +0 -86
  119. data/doc/release_notes/5.77.0.txt +0 -63
  120. data/doc/release_notes/5.78.0.txt +0 -67
  121. data/doc/release_notes/5.79.0.txt +0 -28
  122. data/doc/release_notes/5.8.0.txt +0 -170
  123. data/doc/release_notes/5.80.0.txt +0 -40
  124. data/doc/release_notes/5.81.0.txt +0 -31
  125. data/doc/release_notes/5.82.0.txt +0 -61
  126. data/doc/release_notes/5.9.0.txt +0 -99
  127. data/doc/schema_modification.rdoc +0 -679
  128. data/doc/security.rdoc +0 -443
  129. data/doc/sharding.rdoc +0 -286
  130. data/doc/sql.rdoc +0 -648
  131. data/doc/testing.rdoc +0 -204
  132. data/doc/thread_safety.rdoc +0 -15
  133. data/doc/transactions.rdoc +0 -250
  134. data/doc/validations.rdoc +0 -558
  135. data/doc/virtual_rows.rdoc +0 -265
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f09a139a164322e0a0e52e9a58c79b2f463972363509c41bf50e7082c1f542b7
4
- data.tar.gz: e7222b81a79111b9853565160f81cb18c72b341f18bec839046c9b49a4b199ea
3
+ metadata.gz: 5677b07054121f55f100f0629d8102cabdd9db454263c5199a8f401bea891992
4
+ data.tar.gz: ca57e632e3e66c3a4003f988e5240da6a6eed0de9a143ac3985bd0603e0d9073
5
5
  SHA512:
6
- metadata.gz: d9f16395ad855ccbc4494bd2e1436b6b78f15ddbfd1c9b80d356040d99415a46a352f50042b2fc9ab23d29b65567dafec2fceb35c709498159b00a1402991ee6
7
- data.tar.gz: a5693c2f3c3791c0216a5af9e933edaa41b0eeb030a3523e52a6951c666e720d0b12ec48ae3f46777ce617b27857f6519d7ce98ec1768a0c8226c4b494e501c1
6
+ metadata.gz: 2ea8e58679c4ae2455588b584b959b3be691c177823cf336b77fa7b5910e716d9ca88e54024bbef44ec58d3fa8d66070acbf94e8c32a4294126ab2e618f4285e
7
+ data.tar.gz: acf4e565dd754b16ea0c07a11fe67cd21c9d5833ac1cf70c384a8da2c1b7c9ffd324358dbab9a8196d5a249365cc11870e6c807d07dbc631d359b413977f14ed
data/bin/sequel CHANGED
@@ -18,21 +18,6 @@ load_dirs = []
18
18
  exclusive_options = []
19
19
  loggers = []
20
20
 
21
- logger_class = Class.new do
22
- def initialize(device)
23
- @device = device
24
- end
25
-
26
- def debug(msg)
27
- end
28
-
29
- [:info, :warn, :error].each do |meth|
30
- define_method(meth) do |msg|
31
- @device.puts("#{Time.now.strftime('%Y-%m-%d %T')} #{meth.to_s.upcase}: #{msg}")
32
- end
33
- end
34
- end
35
-
36
21
  options = OptionParser.new do |opts|
37
22
  opts.banner = "Sequel: The Database Toolkit for Ruby"
38
23
  opts.define_head "Usage: sequel [options] <uri|path> [file]"
@@ -76,7 +61,7 @@ options = OptionParser.new do |opts|
76
61
  end
77
62
 
78
63
  opts.on("-E", "--echo", "echo SQL statements") do
79
- loggers << logger_class.new($stdout)
64
+ loggers << $stdout
80
65
  end
81
66
 
82
67
  opts.on("-I", "--include dir", "specify $LOAD_PATH directory") do |v|
@@ -84,7 +69,9 @@ options = OptionParser.new do |opts|
84
69
  end
85
70
 
86
71
  opts.on("-l", "--log logfile", "log SQL statements to log file") do |v|
87
- loggers << logger_class.new(File.open(v, 'a'))
72
+ file = File.open(v, 'a')
73
+ file.sync = true
74
+ loggers << file
88
75
  end
89
76
 
90
77
  opts.on("-L", "--load-dir DIR", "loads all *.rb under specifed directory") do |v|
@@ -168,6 +155,11 @@ begin
168
155
  end
169
156
  end
170
157
 
158
+ unless loggers.empty?
159
+ Sequel.extension :stdio_logger
160
+ loggers.map!{|io| Sequel::StdioLogger.new(io)}
161
+ end
162
+
171
163
  DB = connect_proc[db]
172
164
  load_dirs.each{|d| d.is_a?(Array) ? require(d.first) : Dir["#{d}/**/*.rb"].each{|f| load(f)}}
173
165
  if migrate_dir
@@ -115,7 +115,7 @@ module Sequel
115
115
  # Temporary table creation on Derby uses DECLARE instead of CREATE.
116
116
  def create_table_prefix_sql(name, options)
117
117
  if options[:temp]
118
- "DECLARE GLOBAL TEMPORARY TABLE #{quote_identifier(name)}"
118
+ "DECLARE GLOBAL TEMPORARY TABLE #{create_table_table_name_sql(name, options)}"
119
119
  else
120
120
  super
121
121
  end
@@ -198,7 +198,7 @@ module Sequel
198
198
  # http://www.ibm.com/developerworks/data/library/techarticle/dm-0912globaltemptable/
199
199
  def create_table_prefix_sql(name, options)
200
200
  if options[:temp]
201
- "DECLARE GLOBAL TEMPORARY TABLE #{quote_identifier(name)}"
201
+ "DECLARE GLOBAL TEMPORARY TABLE #{create_table_table_name_sql(name, options)}"
202
202
  else
203
203
  super
204
204
  end
@@ -379,9 +379,21 @@ module Sequel
379
379
  # a regular and temporary table, with temporary table names starting with
380
380
  # a #.
381
381
  def create_table_prefix_sql(name, options)
382
- "CREATE TABLE #{quote_schema_table(options[:temp] ? "##{name}" : name)}"
382
+ "CREATE TABLE #{create_table_table_name_sql(name, options)}"
383
383
  end
384
-
384
+
385
+ # The SQL to use for the table name for a temporary table.
386
+ def create_table_temp_table_name_sql(name, _options)
387
+ case name
388
+ when String, Symbol
389
+ "##{name}"
390
+ when SQL::Identifier
391
+ "##{name.value}"
392
+ else
393
+ raise Error, "temporary table names must be strings, symbols, or Sequel::SQL::Identifier instances on Microsoft SQL Server"
394
+ end
395
+ end
396
+
385
397
  # MSSQL doesn't support CREATE TABLE AS, it only supports SELECT INTO.
386
398
  # Emulating CREATE TABLE AS using SELECT INTO is only possible if a dataset
387
399
  # is given as the argument, it can't work with a string, so raise an
@@ -1429,7 +1429,7 @@ module Sequel
1429
1429
  'UNLOGGED '
1430
1430
  end
1431
1431
 
1432
- "CREATE #{prefix_sql}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{options[:temp] ? quote_identifier(name) : quote_schema_table(name)}"
1432
+ "CREATE #{prefix_sql}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{create_table_table_name_sql(name, options)}"
1433
1433
  end
1434
1434
 
1435
1435
  # SQL for creating a table with PostgreSQL specific options
@@ -2068,6 +2068,19 @@ module Sequel
2068
2068
  end
2069
2069
  end
2070
2070
 
2071
+ # Return a dataset with a WHEN NOT MATCHED BY SOURCE THEN DELETE clause added to the
2072
+ # MERGE statement. If a block is passed, treat it as a virtual row and
2073
+ # use it as additional conditions for the match.
2074
+ #
2075
+ # merge_delete_not_matched_by_source
2076
+ # # WHEN NOT MATCHED BY SOURCE THEN DELETE
2077
+ #
2078
+ # merge_delete_not_matched_by_source{a > 30}
2079
+ # # WHEN NOT MATCHED BY SOURCE AND (a > 30) THEN DELETE
2080
+ def merge_delete_when_not_matched_by_source(&block)
2081
+ _merge_when(:type=>:delete_not_matched_by_source, &block)
2082
+ end
2083
+
2071
2084
  # Return a dataset with a WHEN MATCHED THEN DO NOTHING clause added to the
2072
2085
  # MERGE statement. If a block is passed, treat it as a virtual row and
2073
2086
  # use it as additional conditions for the match.
@@ -2094,6 +2107,19 @@ module Sequel
2094
2107
  _merge_when(:type=>:not_matched, &block)
2095
2108
  end
2096
2109
 
2110
+ # Return a dataset with a WHEN NOT MATCHED BY SOURCE THEN DO NOTHING clause added to the
2111
+ # MERGE BY SOURCE statement. If a block is passed, treat it as a virtual row and
2112
+ # use it as additional conditions for the match.
2113
+ #
2114
+ # merge_do_nothing_when_not_matched_by_source
2115
+ # # WHEN NOT MATCHED BY SOURCE THEN DO NOTHING
2116
+ #
2117
+ # merge_do_nothing_when_not_matched_by_source{a > 30}
2118
+ # # WHEN NOT MATCHED BY SOURCE AND (a > 30) THEN DO NOTHING
2119
+ def merge_do_nothing_when_not_matched_by_source(&block)
2120
+ _merge_when(:type=>:not_matched_by_source, &block)
2121
+ end
2122
+
2097
2123
  # Support OVERRIDING USER|SYSTEM VALUE for MERGE INSERT.
2098
2124
  def merge_insert(*values, &block)
2099
2125
  h = {:type=>:insert, :values=>values}
@@ -2103,6 +2129,19 @@ module Sequel
2103
2129
  _merge_when(h, &block)
2104
2130
  end
2105
2131
 
2132
+ # Return a dataset with a WHEN NOT MATCHED BY SOURCE THEN UPDATE clause added to the
2133
+ # MERGE statement. If a block is passed, treat it as a virtual row and
2134
+ # use it as additional conditions for the match.
2135
+ #
2136
+ # merge_update_not_matched_by_source(i1: Sequel[:i1]+:i2+10, a: Sequel[:a]+:b+20)
2137
+ # # WHEN NOT MATCHED BY SOURCE THEN UPDATE SET i1 = (i1 + i2 + 10), a = (a + b + 20)
2138
+ #
2139
+ # merge_update_not_matched_by_source(i1: :i2){a > 30}
2140
+ # # WHEN NOT MATCHED BY SOURCE AND (a > 30) THEN UPDATE SET i1 = i2
2141
+ def merge_update_when_not_matched_by_source(values, &block)
2142
+ _merge_when(:type=>:update_not_matched_by_source, :values=>values, &block)
2143
+ end
2144
+
2106
2145
  # Use OVERRIDING USER VALUE for INSERT statements, so that identity columns
2107
2146
  # always use the user supplied value, and an error is not raised for identity
2108
2147
  # columns that are GENERATED ALWAYS.
@@ -2296,7 +2335,7 @@ module Sequel
2296
2335
 
2297
2336
  # Append the INSERT sql used in a MERGE
2298
2337
  def _merge_insert_sql(sql, data)
2299
- sql << " THEN INSERT "
2338
+ sql << " THEN INSERT"
2300
2339
  columns, values = _parse_insert_sql_args(data[:values])
2301
2340
  _insert_columns_sql(sql, columns)
2302
2341
  if override = data[:override]
@@ -2305,10 +2344,9 @@ module Sequel
2305
2344
  _insert_values_sql(sql, values)
2306
2345
  end
2307
2346
 
2308
- def _merge_matched_sql(sql, data)
2347
+ def _merge_do_nothing_sql(sql, data)
2309
2348
  sql << " THEN DO NOTHING"
2310
2349
  end
2311
- alias _merge_not_matched_sql _merge_matched_sql
2312
2350
 
2313
2351
  # Support MERGE RETURNING on PostgreSQL 17+.
2314
2352
  def _merge_when_sql(sql)
@@ -349,7 +349,7 @@ module Sequel
349
349
  ps
350
350
  end
351
351
 
352
- # Support creating STRICT AND/OR WITHOUT ROWID tables via :strict and :without_rowid options
352
+ # Support creating STRICT AND/OR WITHOUT ROWID tables via :strict and :without_rowid options, and VIRTUAL tables with :using option.
353
353
  def create_table_sql(name, generator, options)
354
354
  if options[:strict] && options[:without_rowid]
355
355
  "#{super} STRICT, WITHOUT ROWID"
@@ -357,6 +357,8 @@ module Sequel
357
357
  "#{super} STRICT"
358
358
  elsif options[:without_rowid]
359
359
  "#{super} WITHOUT ROWID"
360
+ elsif options[:using]
361
+ "CREATE VIRTUAL TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{create_table_table_name_sql(name, options)} USING #{options[:using]}"
360
362
  else
361
363
  super
362
364
  end
@@ -34,10 +34,7 @@ module Sequel
34
34
  uri = URI.parse(conn_string)
35
35
  scheme = uri.scheme
36
36
  c = adapter_class(scheme)
37
- uri_options = c.send(:uri_to_options, uri)
38
- uri.query.split('&').map{|s| s.split('=')}.each{|k,v| uri_options[k.to_sym] = v if k && !k.empty?} unless uri.query.to_s.strip.empty?
39
- uri_options.to_a.each{|k,v| uri_options[k] = URI::DEFAULT_PARSER.unescape(v) if v.is_a?(String)}
40
- opts = uri_options.merge(opts).merge!(:orig_opts=>opts.dup, :uri=>conn_string, :adapter=>scheme)
37
+ opts = c.send(:options_from_uri, uri).merge!(opts).merge!(:orig_opts=>opts.dup, :uri=>conn_string, :adapter=>scheme)
41
38
  end
42
39
  when Hash
43
40
  opts = conn_string.merge(opts)
@@ -82,6 +82,14 @@ module Sequel
82
82
  end
83
83
  private_class_method :uri_to_options
84
84
 
85
+ def self.options_from_uri(uri)
86
+ uri_options = uri_to_options(uri)
87
+ uri.query.split('&').map{|s| s.split('=')}.each{|k,v| uri_options[k.to_sym] = v if k && !k.empty?} unless uri.query.to_s.strip.empty?
88
+ uri_options.to_a.each{|k,v| uri_options[k] = URI::DEFAULT_PARSER.unescape(v) if v.is_a?(String)}
89
+ uri_options
90
+ end
91
+ private_class_method :options_from_uri
92
+
85
93
  # The options hash for this database
86
94
  attr_reader :opts
87
95
 
@@ -253,15 +261,27 @@ module Sequel
253
261
  Sequel.convert_output_timestamp(v, timezone)
254
262
  end
255
263
 
256
- # Returns a string representation of the database object including the
257
- # class name and connection URI and options used when connecting (if any).
264
+ # Returns a string representation of the Database object, including
265
+ # the database type, host, database, and user, if present.
258
266
  def inspect
259
- a = []
260
- a << uri.inspect if uri
261
- if (oo = opts[:orig_opts]) && !oo.empty?
262
- a << oo.inspect
267
+ s = String.new
268
+ s << "#<#{self.class}"
269
+ s << " database_type=#{database_type}" if database_type && database_type != adapter_scheme
270
+
271
+ keys = [:host, :database, :user]
272
+ opts = self.opts
273
+ if !keys.any?{|k| opts[k]} && opts[:uri]
274
+ opts = self.class.send(:options_from_uri, URI.parse(opts[:uri]))
275
+ end
276
+
277
+ keys.each do |key|
278
+ val = opts[key]
279
+ if val && val != ''
280
+ s << " #{key}=#{val}"
281
+ end
263
282
  end
264
- "#<#{self.class}: #{a.join(' ')}>"
283
+
284
+ s << ">"
265
285
  end
266
286
 
267
287
  # Proxy the literal call to the dataset.
@@ -191,6 +191,8 @@ module Sequel
191
191
  # The +any+ type is treated like a SQLite column in a non-strict table,
192
192
  # allowing any type of data to be stored. This option is supported on
193
193
  # SQLite 3.37.0+.
194
+ # :using :: Create a VIRTUAL table with the given USING clause. The value should be
195
+ # a string, as it is used directly in the SQL query.
194
196
  # :without_rowid :: Create a WITHOUT ROWID table. Every row in SQLite has a special
195
197
  # 'rowid' column, that uniquely identifies that row within the table.
196
198
  # If this option is used, the 'rowid' column is omitted, which can
@@ -775,7 +777,21 @@ module Sequel
775
777
 
776
778
  # SQL fragment for initial part of CREATE TABLE statement
777
779
  def create_table_prefix_sql(name, options)
778
- "CREATE #{temporary_table_sql if options[:temp]}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{options[:temp] ? quote_identifier(name) : quote_schema_table(name)}"
780
+ "CREATE #{temporary_table_sql if options[:temp]}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{create_table_table_name_sql(name, options)}"
781
+ end
782
+
783
+ # The SQL to use for a table name when creating a table.
784
+ # Use of the :temp option can result in different SQL,
785
+ # because the rules for temp table naming can differ
786
+ # between databases, and temp tables should not use the
787
+ # default_schema.
788
+ def create_table_table_name_sql(name, options)
789
+ options[:temp] ? create_table_temp_table_name_sql(name, options) : quote_schema_table(name)
790
+ end
791
+
792
+ # The SQL to use for the table name for a temporary table.
793
+ def create_table_temp_table_name_sql(name, _options)
794
+ name.is_a?(String) ? quote_identifier(name) : literal(name)
779
795
  end
780
796
 
781
797
  # SQL fragment for initial part of CREATE VIEW statement
@@ -901,18 +901,31 @@ module Sequel
901
901
  MERGE_TYPE_SQL = {
902
902
  :insert => ' WHEN NOT MATCHED',
903
903
  :delete => ' WHEN MATCHED',
904
+ :delete_not_matched_by_source => ' WHEN NOT MATCHED BY SOURCE',
904
905
  :update => ' WHEN MATCHED',
906
+ :update_not_matched_by_source => ' WHEN NOT MATCHED BY SOURCE',
905
907
  :matched => ' WHEN MATCHED',
906
908
  :not_matched => ' WHEN NOT MATCHED',
909
+ :not_matched_by_source => ' WHEN NOT MATCHED BY SOURCE',
907
910
  }.freeze
908
911
  private_constant :MERGE_TYPE_SQL
909
912
 
913
+ MERGE_NORMALIZE_TYPE_MAP = {
914
+ :delete_not_matched_by_source => :delete,
915
+ :update_not_matched_by_source => :update,
916
+ :matched => :do_nothing,
917
+ :not_matched => :do_nothing,
918
+ :not_matched_by_source => :do_nothing,
919
+ }.freeze
920
+ private_constant :MERGE_NORMALIZE_TYPE_MAP
921
+
910
922
  # Add the WHEN clauses to the MERGE SQL
911
923
  def _merge_when_sql(sql)
912
924
  raise Error, "no WHEN [NOT] MATCHED clauses provided for MERGE" unless merge_when = @opts[:merge_when]
913
925
  merge_when.each do |data|
914
926
  type = data[:type]
915
927
  sql << MERGE_TYPE_SQL[type]
928
+ type = MERGE_NORMALIZE_TYPE_MAP[type] || type
916
929
  _merge_when_conditions_sql(sql, data)
917
930
  send(:"_merge_#{type}_sql", sql, data)
918
931
  end