sequel 5.57.0 → 5.60.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +34 -0
- data/README.rdoc +25 -0
- data/bin/sequel +11 -3
- data/doc/cheat_sheet.rdoc +8 -0
- data/doc/opening_databases.rdoc +10 -6
- data/doc/release_notes/5.58.0.txt +31 -0
- data/doc/release_notes/5.59.0.txt +73 -0
- data/doc/release_notes/5.60.0.txt +22 -0
- data/doc/testing.rdoc +1 -1
- data/lib/sequel/adapters/jdbc/derby.rb +5 -0
- data/lib/sequel/adapters/jdbc/h2.rb +5 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +6 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
- data/lib/sequel/adapters/jdbc.rb +5 -5
- data/lib/sequel/adapters/mock.rb +1 -1
- data/lib/sequel/adapters/mysql.rb +3 -3
- data/lib/sequel/adapters/oracle.rb +1 -1
- data/lib/sequel/adapters/postgres.rb +58 -17
- data/lib/sequel/adapters/shared/db2.rb +28 -0
- data/lib/sequel/adapters/shared/mssql.rb +35 -1
- data/lib/sequel/adapters/shared/mysql.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +70 -1
- data/lib/sequel/adapters/shared/postgres.rb +94 -18
- data/lib/sequel/adapters/shared/sqlite.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +1 -1
- data/lib/sequel/ast_transformer.rb +1 -1
- data/lib/sequel/database/misc.rb +2 -2
- data/lib/sequel/database/schema_generator.rb +1 -0
- data/lib/sequel/database/schema_methods.rb +3 -0
- data/lib/sequel/dataset/actions.rb +49 -0
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/query.rb +62 -0
- data/lib/sequel/dataset/sql.rb +114 -27
- data/lib/sequel/extensions/date_arithmetic.rb +35 -7
- data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
- data/lib/sequel/extensions/is_distinct_from.rb +3 -1
- data/lib/sequel/extensions/pg_array.rb +2 -2
- data/lib/sequel/extensions/pg_array_ops.rb +1 -1
- data/lib/sequel/extensions/pg_enum.rb +1 -1
- data/lib/sequel/extensions/pg_hstore.rb +1 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +3 -3
- data/lib/sequel/extensions/pg_inet.rb +2 -2
- data/lib/sequel/extensions/pg_interval.rb +1 -1
- data/lib/sequel/extensions/pg_json.rb +1 -1
- data/lib/sequel/extensions/pg_json_ops.rb +55 -3
- data/lib/sequel/extensions/pg_multirange.rb +2 -2
- data/lib/sequel/extensions/pg_range.rb +2 -2
- data/lib/sequel/extensions/pg_row.rb +2 -2
- data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -2
- data/lib/sequel/extensions/symbol_aref.rb +2 -0
- data/lib/sequel/model/associations.rb +18 -6
- data/lib/sequel/model/base.rb +17 -7
- data/lib/sequel/model/exceptions.rb +1 -1
- data/lib/sequel/model/inflections.rb +6 -6
- data/lib/sequel/plugins/auto_validations.rb +1 -1
- data/lib/sequel/plugins/defaults_setter.rb +1 -1
- data/lib/sequel/plugins/dirty.rb +1 -1
- data/lib/sequel/plugins/insert_conflict.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +1 -1
- data/lib/sequel/plugins/list.rb +3 -1
- data/lib/sequel/plugins/nested_attributes.rb +1 -1
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +1 -1
- data/lib/sequel/plugins/require_valid_schema.rb +67 -0
- data/lib/sequel/plugins/serialization.rb +1 -1
- data/lib/sequel/plugins/sharding.rb +1 -1
- data/lib/sequel/plugins/sql_comments.rb +4 -4
- data/lib/sequel/plugins/subclasses.rb +1 -1
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -0
- data/lib/sequel/plugins/validation_class_methods.rb +3 -3
- data/lib/sequel/plugins/validation_helpers.rb +1 -1
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- metadata +9 -16
@@ -5,6 +5,7 @@ require_relative 'shared/postgres'
|
|
5
5
|
begin
|
6
6
|
require 'pg'
|
7
7
|
|
8
|
+
# :nocov:
|
8
9
|
Sequel::Postgres::PGError = PG::Error if defined?(PG::Error)
|
9
10
|
Sequel::Postgres::PGconn = PG::Connection if defined?(PG::Connection)
|
10
11
|
Sequel::Postgres::PGresult = PG::Result if defined?(PG::Result)
|
@@ -14,30 +15,40 @@ begin
|
|
14
15
|
raise LoadError unless defined?(PGconn::CONNECTION_OK)
|
15
16
|
end
|
16
17
|
|
17
|
-
Sequel::Postgres::USES_PG = true
|
18
18
|
if defined?(PG::TypeMapByClass)
|
19
|
+
# :nocov:
|
19
20
|
type_map = Sequel::Postgres::PG_QUERY_TYPE_MAP = PG::TypeMapByClass.new
|
20
21
|
type_map[Integer] = PG::TextEncoder::Integer.new
|
21
22
|
type_map[FalseClass] = type_map[TrueClass] = PG::TextEncoder::Boolean.new
|
22
23
|
type_map[Float] = PG::TextEncoder::Float.new
|
23
24
|
end
|
25
|
+
|
26
|
+
Sequel::Postgres::USES_PG = true
|
24
27
|
rescue LoadError => e
|
28
|
+
# :nocov:
|
25
29
|
begin
|
26
|
-
require 'postgres-pr
|
27
|
-
Sequel::Postgres::USES_PG = false
|
30
|
+
require 'sequel/postgres-pr'
|
28
31
|
rescue LoadError
|
29
|
-
|
32
|
+
begin
|
33
|
+
require 'postgres-pr/postgres-compat'
|
34
|
+
rescue LoadError
|
35
|
+
raise e
|
36
|
+
end
|
30
37
|
end
|
38
|
+
Sequel::Postgres::USES_PG = false
|
39
|
+
# :nocov:
|
31
40
|
end
|
32
41
|
|
33
42
|
module Sequel
|
34
43
|
module Postgres
|
35
|
-
|
44
|
+
# :nocov:
|
45
|
+
if USES_PG
|
36
46
|
# Whether the given sequel_pg version integer is supported.
|
37
47
|
def self.sequel_pg_version_supported?(version)
|
38
48
|
version >= 10617
|
39
49
|
end
|
40
50
|
end
|
51
|
+
# :nocov:
|
41
52
|
|
42
53
|
# PGconn subclass for connection specific methods used with the
|
43
54
|
# pg or postgres-pr driver.
|
@@ -45,7 +56,9 @@ module Sequel
|
|
45
56
|
# The underlying exception classes to reraise as disconnect errors
|
46
57
|
# instead of regular database errors.
|
47
58
|
DISCONNECT_ERROR_CLASSES = [IOError, Errno::EPIPE, Errno::ECONNRESET]
|
59
|
+
# :nocov:
|
48
60
|
if defined?(::PG::ConnectionBad)
|
61
|
+
# :nocov:
|
49
62
|
DISCONNECT_ERROR_CLASSES << ::PG::ConnectionBad
|
50
63
|
end
|
51
64
|
DISCONNECT_ERROR_CLASSES.freeze
|
@@ -71,11 +84,14 @@ module Sequel
|
|
71
84
|
# are SQL strings.
|
72
85
|
attr_reader :prepared_statements
|
73
86
|
|
87
|
+
# :nocov:
|
74
88
|
unless public_method_defined?(:async_exec_params)
|
75
89
|
alias async_exec_params async_exec
|
76
90
|
end
|
77
|
-
|
78
|
-
#
|
91
|
+
elsif !const_defined?(:CONNECTION_OK)
|
92
|
+
# Handle old postgres-pr
|
93
|
+
# sequel-postgres-pr already implements this API
|
94
|
+
|
79
95
|
CONNECTION_OK = -1
|
80
96
|
|
81
97
|
# Escape bytea values. Uses historical format instead of hex
|
@@ -111,6 +127,7 @@ module Sequel
|
|
111
127
|
alias cmd_tuples cmdtuples
|
112
128
|
end
|
113
129
|
end
|
130
|
+
# :nocov:
|
114
131
|
|
115
132
|
# Raise a Sequel::DatabaseDisconnectError if a one of the disconnect
|
116
133
|
# error classes is raised, or a PGError is raised and the connection
|
@@ -143,7 +160,7 @@ module Sequel
|
|
143
160
|
begin
|
144
161
|
defined?(yield) ? yield(q) : q.cmd_tuples
|
145
162
|
ensure
|
146
|
-
q.clear if q && q.
|
163
|
+
q.clear if q && defined?(q.clear)
|
147
164
|
end
|
148
165
|
end
|
149
166
|
|
@@ -204,7 +221,9 @@ module Sequel
|
|
204
221
|
:sslmode => opts[:sslmode],
|
205
222
|
:sslrootcert => opts[:sslrootcert]
|
206
223
|
}.delete_if { |key, value| blank_object?(value) }
|
224
|
+
# :nocov:
|
207
225
|
connection_params.merge!(opts[:driver_options]) if opts[:driver_options]
|
226
|
+
# :nocov:
|
208
227
|
conn = Adapter.connect(opts[:conn_str] || connection_params)
|
209
228
|
|
210
229
|
conn.instance_variable_set(:@prepared_statements, {})
|
@@ -212,6 +231,13 @@ module Sequel
|
|
212
231
|
if receiver = opts[:notice_receiver]
|
213
232
|
conn.set_notice_receiver(&receiver)
|
214
233
|
end
|
234
|
+
|
235
|
+
# :nocov:
|
236
|
+
if conn.respond_to?(:type_map_for_queries=) && defined?(PG_QUERY_TYPE_MAP)
|
237
|
+
# :nocov:
|
238
|
+
conn.type_map_for_queries = PG_QUERY_TYPE_MAP
|
239
|
+
end
|
240
|
+
# :nocov:
|
215
241
|
else
|
216
242
|
unless typecast_value_boolean(@opts.fetch(:force_standard_strings, true))
|
217
243
|
raise Error, "Cannot create connection using postgres-pr unless force_standard_strings is set"
|
@@ -226,19 +252,19 @@ module Sequel
|
|
226
252
|
opts[:password]
|
227
253
|
)
|
228
254
|
end
|
255
|
+
# :nocov:
|
229
256
|
|
230
257
|
conn.instance_variable_set(:@db, self)
|
231
|
-
if USES_PG && conn.respond_to?(:type_map_for_queries=) && defined?(PG_QUERY_TYPE_MAP)
|
232
|
-
conn.type_map_for_queries = PG_QUERY_TYPE_MAP
|
233
|
-
end
|
234
258
|
|
259
|
+
# :nocov:
|
235
260
|
if encoding = opts[:encoding] || opts[:charset]
|
236
|
-
if conn.
|
261
|
+
if defined?(conn.set_client_encoding)
|
237
262
|
conn.set_client_encoding(encoding)
|
238
263
|
else
|
239
264
|
conn.async_exec("set client_encoding to '#{encoding}'")
|
240
265
|
end
|
241
266
|
end
|
267
|
+
# :nocov:
|
242
268
|
|
243
269
|
connection_configuration_sqls(opts).each{|sql| conn.execute(sql)}
|
244
270
|
conn
|
@@ -265,7 +291,9 @@ module Sequel
|
|
265
291
|
nil
|
266
292
|
end
|
267
293
|
|
294
|
+
# :nocov:
|
268
295
|
if USES_PG && Object.const_defined?(:PG) && ::PG.const_defined?(:Constants) && ::PG::Constants.const_defined?(:PG_DIAG_SCHEMA_NAME)
|
296
|
+
# :nocov:
|
269
297
|
# Return a hash of information about the related PGError (or Sequel::DatabaseError that
|
270
298
|
# wraps a PGError), with the following entries (any of which may be +nil+):
|
271
299
|
#
|
@@ -316,7 +344,9 @@ module Sequel
|
|
316
344
|
synchronize(opts[:server]){|conn| check_database_errors{_execute(conn, sql, opts, &block)}}
|
317
345
|
end
|
318
346
|
|
347
|
+
# :nocov:
|
319
348
|
if USES_PG
|
349
|
+
# :nocov:
|
320
350
|
# +copy_table+ uses PostgreSQL's +COPY TO STDOUT+ SQL statement to return formatted
|
321
351
|
# results directly to the caller. This method is only supported if pg is the
|
322
352
|
# underlying ruby driver. This method should only be called if you want
|
@@ -462,12 +492,12 @@ module Sequel
|
|
462
492
|
opts[:after_listen].call(conn) if opts[:after_listen]
|
463
493
|
timeout = opts[:timeout]
|
464
494
|
if timeout
|
465
|
-
timeout_block = timeout.
|
495
|
+
timeout_block = defined?(timeout.call) ? timeout : proc{timeout}
|
466
496
|
end
|
467
497
|
|
468
498
|
if l = opts[:loop]
|
469
499
|
raise Error, 'calling #listen with :loop requires a block' unless block
|
470
|
-
loop_call = l.
|
500
|
+
loop_call = defined?(l.call)
|
471
501
|
catch(:stop) do
|
472
502
|
while true
|
473
503
|
t = timeout_block ? [timeout_block.call] : []
|
@@ -509,8 +539,10 @@ module Sequel
|
|
509
539
|
def adapter_initialize
|
510
540
|
@use_iso_date_format = typecast_value_boolean(@opts.fetch(:use_iso_date_format, true))
|
511
541
|
initialize_postgres_adapter
|
542
|
+
# :nocov:
|
512
543
|
add_conversion_proc(17, method(:unescape_bytea)) if USES_PG
|
513
544
|
add_conversion_proc(1082, TYPE_TRANSLATOR_DATE) if @use_iso_date_format
|
545
|
+
# :nocov:
|
514
546
|
self.convert_infinite_timestamps = @opts[:convert_infinite_timestamps]
|
515
547
|
end
|
516
548
|
|
@@ -520,19 +552,22 @@ module Sequel
|
|
520
552
|
rescue => e
|
521
553
|
raise_error(e, :classes=>database_error_classes)
|
522
554
|
end
|
523
|
-
|
524
555
|
# Set the DateStyle to ISO if configured, for faster date parsing.
|
525
556
|
def connection_configuration_sqls(opts=@opts)
|
526
557
|
sqls = super
|
558
|
+
# :nocov:
|
527
559
|
sqls << "SET DateStyle = 'ISO'" if @use_iso_date_format
|
560
|
+
# :nocov:
|
528
561
|
sqls
|
529
562
|
end
|
530
563
|
|
564
|
+
# :nocov:
|
531
565
|
if USES_PG
|
532
566
|
def unescape_bytea(s)
|
533
567
|
::Sequel::SQL::Blob.new(Adapter.unescape_bytea(s))
|
534
568
|
end
|
535
569
|
end
|
570
|
+
# :nocov:
|
536
571
|
|
537
572
|
DATABASE_ERROR_CLASSES = [PGError].freeze
|
538
573
|
def database_error_classes
|
@@ -546,7 +581,9 @@ module Sequel
|
|
546
581
|
end
|
547
582
|
|
548
583
|
def database_exception_sqlstate(exception, opts)
|
549
|
-
|
584
|
+
# :nocov:
|
585
|
+
if defined?(exception.result) && (result = exception.result)
|
586
|
+
# :nocov:
|
550
587
|
result.error_field(PGresult::PG_DIAG_SQLSTATE)
|
551
588
|
end
|
552
589
|
end
|
@@ -588,7 +625,7 @@ module Sequel
|
|
588
625
|
begin
|
589
626
|
defined?(yield) ? yield(q) : q.cmd_tuples
|
590
627
|
ensure
|
591
|
-
q.clear if q && q.
|
628
|
+
q.clear if q && defined?(q.clear)
|
592
629
|
end
|
593
630
|
end
|
594
631
|
|
@@ -656,7 +693,9 @@ module Sequel
|
|
656
693
|
clone(:where=>Sequel.lit(['CURRENT OF '], Sequel.identifier(cursor_name)))
|
657
694
|
end
|
658
695
|
|
696
|
+
# :nocov:
|
659
697
|
if USES_PG
|
698
|
+
# :nocov:
|
660
699
|
PREPARED_ARG_PLACEHOLDER = LiteralString.new('$').freeze
|
661
700
|
|
662
701
|
# PostgreSQL specific argument mapper used for mapping the named
|
@@ -803,6 +842,7 @@ module Sequel
|
|
803
842
|
end
|
804
843
|
end
|
805
844
|
|
845
|
+
# :nocov:
|
806
846
|
if Sequel::Postgres::USES_PG && !ENV['NO_SEQUEL_PG']
|
807
847
|
begin
|
808
848
|
require 'sequel_pg'
|
@@ -814,3 +854,4 @@ if Sequel::Postgres::USES_PG && !ENV['NO_SEQUEL_PG']
|
|
814
854
|
rescue LoadError
|
815
855
|
end
|
816
856
|
end
|
857
|
+
# :nocov:
|
@@ -338,6 +338,11 @@ module Sequel
|
|
338
338
|
true
|
339
339
|
end
|
340
340
|
|
341
|
+
# DB2 supports MERGE
|
342
|
+
def supports_merge?
|
343
|
+
true
|
344
|
+
end
|
345
|
+
|
341
346
|
# DB2 does not support multiple columns in IN.
|
342
347
|
def supports_multiple_column_in?
|
343
348
|
false
|
@@ -360,6 +365,29 @@ module Sequel
|
|
360
365
|
|
361
366
|
private
|
362
367
|
|
368
|
+
# Normalize conditions for MERGE WHEN.
|
369
|
+
def _merge_when_conditions_sql(sql, data)
|
370
|
+
if data.has_key?(:conditions)
|
371
|
+
sql << " AND "
|
372
|
+
literal_append(sql, _normalize_merge_when_conditions(data[:conditions]))
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
# Handle nil, false, and true MERGE WHEN conditions to avoid non-boolean
|
377
|
+
# type error.
|
378
|
+
def _normalize_merge_when_conditions(conditions)
|
379
|
+
case conditions
|
380
|
+
when nil, false
|
381
|
+
{1=>0}
|
382
|
+
when true
|
383
|
+
{1=>1}
|
384
|
+
when Sequel::SQL::DelayedEvaluation
|
385
|
+
Sequel.delay{_normalize_merge_when_conditions(conditions.call(self))}
|
386
|
+
else
|
387
|
+
conditions
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
363
391
|
def empty_from_sql
|
364
392
|
' FROM "SYSIBM"."SYSDUMMY1"'
|
365
393
|
end
|
@@ -205,7 +205,7 @@ module Sequel
|
|
205
205
|
return @server_version = Integer(@opts[:server_version])
|
206
206
|
end
|
207
207
|
@server_version = synchronize(server) do |conn|
|
208
|
-
(conn.server_version rescue nil) if conn.
|
208
|
+
(conn.server_version rescue nil) if defined?(conn.server_version)
|
209
209
|
end
|
210
210
|
unless @server_version
|
211
211
|
m = /^(\d+)\.(\d+)\.(\d+)/.match(fetch("SELECT CAST(SERVERPROPERTY('ProductVersion') AS varchar)").single_value.to_s)
|
@@ -734,6 +734,11 @@ module Sequel
|
|
734
734
|
false
|
735
735
|
end
|
736
736
|
|
737
|
+
# MSSQL 2008+ supports MERGE
|
738
|
+
def supports_merge?
|
739
|
+
is_2008_or_later?
|
740
|
+
end
|
741
|
+
|
737
742
|
# MSSQL 2005+ supports modifying joined datasets
|
738
743
|
def supports_modifying_joins?
|
739
744
|
is_2005_or_later?
|
@@ -824,6 +829,35 @@ module Sequel
|
|
824
829
|
|
825
830
|
private
|
826
831
|
|
832
|
+
# Normalize conditions for MERGE WHEN.
|
833
|
+
def _merge_when_conditions_sql(sql, data)
|
834
|
+
if data.has_key?(:conditions)
|
835
|
+
sql << " AND "
|
836
|
+
literal_append(sql, _normalize_merge_when_conditions(data[:conditions]))
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
# Handle nil, false, and true MERGE WHEN conditions to avoid non-boolean
|
841
|
+
# type error.
|
842
|
+
def _normalize_merge_when_conditions(conditions)
|
843
|
+
case conditions
|
844
|
+
when nil, false
|
845
|
+
{1=>0}
|
846
|
+
when true
|
847
|
+
{1=>1}
|
848
|
+
when Sequel::SQL::DelayedEvaluation
|
849
|
+
Sequel.delay{_normalize_merge_when_conditions(conditions.call(self))}
|
850
|
+
else
|
851
|
+
conditions
|
852
|
+
end
|
853
|
+
end
|
854
|
+
|
855
|
+
# MSSQL requires a semicolon at the end of MERGE.
|
856
|
+
def _merge_when_sql(sql)
|
857
|
+
super
|
858
|
+
sql << ';'
|
859
|
+
end
|
860
|
+
|
827
861
|
# MSSQL does not allow ordering in sub-clauses unless TOP (limit) is specified
|
828
862
|
def aggregate_dataset
|
829
863
|
(options_overlap(Sequel::Dataset::COUNT_FROM_SELF_OPTS) && !options_overlap([:limit])) ? unordered.from_self : super
|
@@ -333,6 +333,12 @@ module Sequel
|
|
333
333
|
sqls << "SET sql_mode = '#{sql_mode}'"
|
334
334
|
end
|
335
335
|
|
336
|
+
# Disable the use of split_materialized in the optimizer. This is
|
337
|
+
# needed to pass association tests on MariaDB 10.5+.
|
338
|
+
if opts[:disable_split_materialized] && typecast_value_boolean(opts[:disable_split_materialized])
|
339
|
+
sqls << "SET SESSION optimizer_switch='split_materialized=off'"
|
340
|
+
end
|
341
|
+
|
336
342
|
sqls
|
337
343
|
end
|
338
344
|
|
@@ -121,7 +121,7 @@ module Sequel
|
|
121
121
|
def server_version(server=nil)
|
122
122
|
return @server_version if @server_version
|
123
123
|
@server_version = synchronize(server) do |conn|
|
124
|
-
(conn.server_version rescue nil) if conn.
|
124
|
+
(conn.server_version rescue nil) if defined?(conn.server_version)
|
125
125
|
end
|
126
126
|
unless @server_version
|
127
127
|
@server_version = if m = /(\d+)\.(\d+)\.?(\d+)?\.?(\d+)?/.match(fetch("select version from PRODUCT_COMPONENT_VERSION where lower(product) like 'oracle%'").single_value)
|
@@ -478,6 +478,11 @@ module Sequel
|
|
478
478
|
false
|
479
479
|
end
|
480
480
|
|
481
|
+
# Oracle supports MERGE
|
482
|
+
def supports_merge?
|
483
|
+
true
|
484
|
+
end
|
485
|
+
|
481
486
|
# Oracle supports NOWAIT.
|
482
487
|
def supports_nowait?
|
483
488
|
true
|
@@ -525,6 +530,70 @@ module Sequel
|
|
525
530
|
|
526
531
|
private
|
527
532
|
|
533
|
+
# Handle nil, false, and true MERGE WHEN conditions to avoid non-boolean
|
534
|
+
# type error.
|
535
|
+
def _normalize_merge_when_conditions(conditions)
|
536
|
+
case conditions
|
537
|
+
when nil, false
|
538
|
+
{1=>0}
|
539
|
+
when true
|
540
|
+
{1=>1}
|
541
|
+
when Sequel::SQL::DelayedEvaluation
|
542
|
+
Sequel.delay{_normalize_merge_when_conditions(conditions.call(self))}
|
543
|
+
else
|
544
|
+
conditions
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
# Handle Oracle's non standard MERGE syntax
|
549
|
+
def _merge_when_sql(sql)
|
550
|
+
raise Error, "no WHEN [NOT] MATCHED clauses provided for MERGE" unless merge_when = @opts[:merge_when]
|
551
|
+
insert = update = delete = nil
|
552
|
+
types = merge_when.map{|d| d[:type]}
|
553
|
+
raise Error, "Oracle does not support multiple INSERT, UPDATE, or DELETE clauses in MERGE" if types != types.uniq
|
554
|
+
|
555
|
+
merge_when.each do |data|
|
556
|
+
case data[:type]
|
557
|
+
when :insert
|
558
|
+
insert = data
|
559
|
+
when :update
|
560
|
+
update = data
|
561
|
+
else # when :delete
|
562
|
+
delete = data
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
if delete
|
567
|
+
raise Error, "Oracle does not support DELETE without UPDATE clause in MERGE" unless update
|
568
|
+
raise Error, "Oracle does not support DELETE without conditions clause in MERGE" unless delete.has_key?(:conditions)
|
569
|
+
end
|
570
|
+
|
571
|
+
if update
|
572
|
+
sql << " WHEN MATCHED"
|
573
|
+
_merge_update_sql(sql, update)
|
574
|
+
_merge_when_conditions_sql(sql, update)
|
575
|
+
|
576
|
+
if delete
|
577
|
+
sql << " DELETE"
|
578
|
+
_merge_when_conditions_sql(sql, delete)
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
if insert
|
583
|
+
sql << " WHEN NOT MATCHED"
|
584
|
+
_merge_insert_sql(sql, insert)
|
585
|
+
_merge_when_conditions_sql(sql, insert)
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
# Handle Oracle's non-standard MERGE WHEN condition syntax.
|
590
|
+
def _merge_when_conditions_sql(sql, data)
|
591
|
+
if data.has_key?(:conditions)
|
592
|
+
sql << " WHERE "
|
593
|
+
literal_append(sql, _normalize_merge_when_conditions(data[:conditions]))
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
528
597
|
# Allow preparing prepared statements, since determining the prepared sql to use for
|
529
598
|
# a prepared statement requires calling prepare on that statement.
|
530
599
|
def allow_preparing_prepared_statements?
|