sequel 5.7.1 → 5.8.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.
- checksums.yaml +4 -4
- data/CHANGELOG +53 -1
- data/doc/association_basics.rdoc +2 -2
- data/doc/migration.rdoc +11 -10
- data/doc/postgresql.rdoc +71 -0
- data/doc/release_notes/5.8.0.txt +170 -0
- data/lib/sequel/adapters/jdbc.rb +6 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -3
- data/lib/sequel/adapters/mysql2.rb +2 -1
- data/lib/sequel/adapters/postgres.rb +32 -10
- data/lib/sequel/adapters/shared/mssql.rb +11 -11
- data/lib/sequel/adapters/shared/mysql.rb +51 -6
- data/lib/sequel/adapters/shared/oracle.rb +12 -2
- data/lib/sequel/adapters/shared/postgres.rb +97 -30
- data/lib/sequel/adapters/shared/sqlanywhere.rb +2 -2
- data/lib/sequel/adapters/shared/sqlite.rb +6 -1
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/query.rb +48 -19
- data/lib/sequel/exceptions.rb +7 -0
- data/lib/sequel/extensions/connection_expiration.rb +8 -3
- data/lib/sequel/extensions/pg_enum.rb +28 -5
- data/lib/sequel/plugins/association_proxies.rb +16 -4
- data/lib/sequel/plugins/error_splitter.rb +16 -11
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +260 -0
- data/lib/sequel/plugins/subclasses.rb +1 -1
- data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/mysql_spec.rb +0 -1
- data/spec/adapters/postgres_spec.rb +169 -4
- data/spec/adapters/sqlite_spec.rb +13 -0
- data/spec/core/dataset_spec.rb +21 -0
- data/spec/extensions/association_proxies_spec.rb +21 -7
- data/spec/extensions/connection_expiration_spec.rb +13 -1
- data/spec/extensions/pg_auto_constraint_validations_spec.rb +165 -0
- data/spec/extensions/pg_enum_spec.rb +26 -22
- data/spec/extensions/tactical_eager_loading_spec.rb +11 -0
- data/spec/integration/dataset_test.rb +30 -6
- data/spec/integration/plugin_test.rb +2 -2
- metadata +6 -2
@@ -342,6 +342,7 @@ module Sequel
|
|
342
342
|
/conflicted with the CHECK constraint/ => CheckConstraintViolation,
|
343
343
|
/column does not allow nulls/ => NotNullConstraintViolation,
|
344
344
|
/was deadlocked on lock resources with another process and has been chosen as the deadlock victim/ => SerializationFailure,
|
345
|
+
/Lock request time out period exceeded\./ => DatabaseLockTimeout,
|
345
346
|
}.freeze
|
346
347
|
def database_error_regexps
|
347
348
|
DATABASE_ERROR_REGEXPS
|
@@ -712,6 +713,11 @@ module Sequel
|
|
712
713
|
false
|
713
714
|
end
|
714
715
|
|
716
|
+
# MSSQL supports NOWAIT.
|
717
|
+
def supports_nowait?
|
718
|
+
true
|
719
|
+
end
|
720
|
+
|
715
721
|
# MSSQL 2012+ supports offsets in correlated subqueries.
|
716
722
|
def supports_offsets_in_correlated_subqueries?
|
717
723
|
is_2012_or_later?
|
@@ -958,6 +964,7 @@ module Sequel
|
|
958
964
|
def select_lock_sql(sql)
|
959
965
|
lock = @opts[:lock]
|
960
966
|
skip_locked = @opts[:skip_locked]
|
967
|
+
nowait = @opts[:nowait]
|
961
968
|
for_update = lock == :update
|
962
969
|
dirty = lock == :dirty
|
963
970
|
lock_hint = for_update || dirty
|
@@ -966,19 +973,12 @@ module Sequel
|
|
966
973
|
sql << " WITH ("
|
967
974
|
|
968
975
|
if lock_hint
|
969
|
-
sql <<
|
970
|
-
'UPDLOCK'
|
971
|
-
else
|
972
|
-
'NOLOCK'
|
973
|
-
end
|
974
|
-
end
|
975
|
-
|
976
|
-
if lock_hint && skip_locked
|
977
|
-
sql << ', '
|
976
|
+
sql << (for_update ? 'UPDLOCK' : 'NOLOCK')
|
978
977
|
end
|
979
978
|
|
980
|
-
if skip_locked
|
981
|
-
sql <<
|
979
|
+
if skip_locked || nowait
|
980
|
+
sql << ', ' if lock_hint
|
981
|
+
sql << (skip_locked ? "READPAST" : "NOWAIT")
|
982
982
|
end
|
983
983
|
|
984
984
|
sql << ')'
|
@@ -58,6 +58,7 @@ module Sequel
|
|
58
58
|
where(:TABLE_NAME=>im.call(table), :TABLE_SCHEMA=>Sequel.function(:DATABASE)).
|
59
59
|
exclude(:CONSTRAINT_NAME=>'PRIMARY').
|
60
60
|
exclude(:REFERENCED_TABLE_NAME=>nil).
|
61
|
+
order(:CONSTRAINT_NAME, :POSITION_IN_UNIQUE_CONSTRAINT).
|
61
62
|
select(Sequel[:CONSTRAINT_NAME].as(:name), Sequel[:COLUMN_NAME].as(:column), Sequel[:REFERENCED_TABLE_NAME].as(:table), Sequel[:REFERENCED_COLUMN_NAME].as(:key))
|
62
63
|
|
63
64
|
h = {}
|
@@ -407,6 +408,7 @@ module Sequel
|
|
407
408
|
/cannot be null/ => NotNullConstraintViolation,
|
408
409
|
/Deadlock found when trying to get lock; try restarting transaction/ => SerializationFailure,
|
409
410
|
/CONSTRAINT .+ failed for/ => CheckConstraintViolation,
|
411
|
+
/\AStatement aborted because lock\(s\) could not be acquired immediately and NOWAIT is set\./ => DatabaseLockTimeout,
|
410
412
|
}.freeze
|
411
413
|
def database_error_regexps
|
412
414
|
DATABASE_ERROR_REGEXPS
|
@@ -561,10 +563,10 @@ module Sequel
|
|
561
563
|
MATCH_AGAINST = ["MATCH ".freeze, " AGAINST (".freeze, ")".freeze].freeze
|
562
564
|
MATCH_AGAINST_BOOLEAN = ["MATCH ".freeze, " AGAINST (".freeze, " IN BOOLEAN MODE)".freeze].freeze
|
563
565
|
|
564
|
-
Dataset.def_sql_method(self, :delete, %w'delete from where order limit')
|
566
|
+
Dataset.def_sql_method(self, :delete, %w'with delete from where order limit')
|
565
567
|
Dataset.def_sql_method(self, :insert, %w'insert ignore into columns values on_duplicate_key_update')
|
566
568
|
Dataset.def_sql_method(self, :select, %w'with select distinct calc_found_rows columns from join where group having compounds order limit lock')
|
567
|
-
Dataset.def_sql_method(self, :update, %w'update ignore table set where order limit')
|
569
|
+
Dataset.def_sql_method(self, :update, %w'with update ignore table set where order limit')
|
568
570
|
|
569
571
|
include Sequel::Dataset::Replace
|
570
572
|
include UnmodifiedIdentifiers::DatasetMethods
|
@@ -579,6 +581,12 @@ module Sequel
|
|
579
581
|
super
|
580
582
|
end
|
581
583
|
when :~, :'!~', :'~*', :'!~*', :LIKE, :'NOT LIKE', :ILIKE, :'NOT ILIKE'
|
584
|
+
if !db.mariadb? && db.server_version >= 80000 && [:~, :'!~'].include?(op)
|
585
|
+
func = Sequel.function(:REGEXP_LIKE, args[0], args[1], 'c')
|
586
|
+
func = ~func if op == :'!~'
|
587
|
+
return literal_append(sql, func)
|
588
|
+
end
|
589
|
+
|
582
590
|
sql << '('
|
583
591
|
literal_append(sql, args[0])
|
584
592
|
sql << ' '
|
@@ -651,7 +659,7 @@ module Sequel
|
|
651
659
|
# Load the PrettyTable class, needed for explain output
|
652
660
|
Sequel.extension(:_pretty_table) unless defined?(Sequel::PrettyTable)
|
653
661
|
|
654
|
-
ds = db.send(:metadata_dataset).with_sql((opts[:extended] ? 'EXPLAIN EXTENDED ' : 'EXPLAIN ') + select_sql).naked
|
662
|
+
ds = db.send(:metadata_dataset).with_sql(((opts[:extended] && (db.mariadb? || db.server_version < 50700)) ? 'EXPLAIN EXTENDED ' : 'EXPLAIN ') + select_sql).naked
|
655
663
|
rows = ds.all
|
656
664
|
Sequel::PrettyTable.string(rows, ds.columns)
|
657
665
|
end
|
@@ -731,8 +739,16 @@ module Sequel
|
|
731
739
|
sql << '`' << c.to_s.gsub('`', '``') << '`'
|
732
740
|
end
|
733
741
|
|
742
|
+
# MariaDB 10.2+ and MySQL 8+ support CTEs
|
734
743
|
def supports_cte?(type=:select)
|
735
|
-
|
744
|
+
if db.mariadb?
|
745
|
+
type == :select && db.server_version >= 100200
|
746
|
+
else
|
747
|
+
case type
|
748
|
+
when :select, :update, :delete
|
749
|
+
db.server_version >= 80000
|
750
|
+
end
|
751
|
+
end
|
736
752
|
end
|
737
753
|
|
738
754
|
# MySQL does not support derived column lists
|
@@ -766,6 +782,11 @@ module Sequel
|
|
766
782
|
true
|
767
783
|
end
|
768
784
|
|
785
|
+
# MySQL 8+ supports NOWAIT.
|
786
|
+
def supports_nowait?
|
787
|
+
!db.mariadb? && db.server_version >= 80000
|
788
|
+
end
|
789
|
+
|
769
790
|
# MySQL's DISTINCT ON emulation using GROUP BY does not respect the
|
770
791
|
# query's ORDER BY clause.
|
771
792
|
def supports_ordered_distinct_on?
|
@@ -777,14 +798,20 @@ module Sequel
|
|
777
798
|
true
|
778
799
|
end
|
779
800
|
|
801
|
+
# MySQL 8+ supports SKIP LOCKED.
|
802
|
+
def supports_skip_locked?
|
803
|
+
!db.mariadb? && db.server_version >= 80000
|
804
|
+
end
|
805
|
+
|
780
806
|
# Check the database setting for whether fractional timestamps
|
781
807
|
# are suppported.
|
782
808
|
def supports_timestamp_usecs?
|
783
809
|
db.supports_timestamp_usecs?
|
784
810
|
end
|
785
811
|
|
812
|
+
# MariaDB 10.2+ and MySQL 8+ support window functions
|
786
813
|
def supports_window_functions?
|
787
|
-
db.
|
814
|
+
db.server_version >= (db.mariadb? ? 100200 : 80000)
|
788
815
|
end
|
789
816
|
|
790
817
|
# Sets up the update methods to use UPDATE IGNORE.
|
@@ -946,8 +973,26 @@ module Sequel
|
|
946
973
|
end
|
947
974
|
|
948
975
|
# Support FOR SHARE locking when using the :share lock style.
|
976
|
+
# Use SKIP LOCKED if skipping locked rows.
|
949
977
|
def select_lock_sql(sql)
|
950
|
-
@opts[:lock]
|
978
|
+
lock = @opts[:lock]
|
979
|
+
if lock == :share
|
980
|
+
if !db.mariadb? && db.server_version >= 80000
|
981
|
+
sql << ' FOR SHARE'
|
982
|
+
else
|
983
|
+
sql << ' LOCK IN SHARE MODE'
|
984
|
+
end
|
985
|
+
else
|
986
|
+
super
|
987
|
+
end
|
988
|
+
|
989
|
+
if lock
|
990
|
+
if @opts[:skip_locked]
|
991
|
+
sql << " SKIP LOCKED"
|
992
|
+
elsif @opts[:nowait]
|
993
|
+
sql << " NOWAIT"
|
994
|
+
end
|
995
|
+
end
|
951
996
|
end
|
952
997
|
|
953
998
|
# MySQL specific SQL_CALC_FOUND_ROWS option
|
@@ -225,6 +225,7 @@ module Sequel
|
|
225
225
|
/check constraint .+ violated/ => CheckConstraintViolation,
|
226
226
|
/cannot insert NULL into|cannot update .+ to NULL/ => NotNullConstraintViolation,
|
227
227
|
/can't serialize access for this transaction/ => SerializationFailure,
|
228
|
+
/resource busy and acquire with NOWAIT specified or timeout/ => DatabaseLockTimeout,
|
228
229
|
}.freeze
|
229
230
|
def database_error_regexps
|
230
231
|
DATABASE_ERROR_REGEXPS
|
@@ -487,6 +488,11 @@ module Sequel
|
|
487
488
|
false
|
488
489
|
end
|
489
490
|
|
491
|
+
# Oracle supports NOWAIT.
|
492
|
+
def supports_nowait?
|
493
|
+
true
|
494
|
+
end
|
495
|
+
|
490
496
|
# Oracle does not support offsets in correlated subqueries.
|
491
497
|
def supports_offsets_in_correlated_subqueries?
|
492
498
|
false
|
@@ -622,8 +628,12 @@ module Sequel
|
|
622
628
|
def select_lock_sql(sql)
|
623
629
|
super
|
624
630
|
|
625
|
-
if @opts[:
|
626
|
-
|
631
|
+
if @opts[:lock]
|
632
|
+
if @opts[:skip_locked]
|
633
|
+
sql << " SKIP LOCKED"
|
634
|
+
elsif @opts[:nowait]
|
635
|
+
sql << " NOWAIT"
|
636
|
+
end
|
627
637
|
end
|
628
638
|
end
|
629
639
|
|
@@ -213,6 +213,32 @@ module Sequel
|
|
213
213
|
run("COMMIT PREPARED #{literal(transaction_id)}", opts)
|
214
214
|
end
|
215
215
|
|
216
|
+
# A hash of metadata for CHECK constraints on the table.
|
217
|
+
# Keys are CHECK constraint name symbols. Values are hashes with the following keys:
|
218
|
+
# :definition :: An SQL fragment for the definition of the constraint
|
219
|
+
# :columns :: An array of column symbols for the columns referenced in the constraint
|
220
|
+
def check_constraints(table)
|
221
|
+
m = output_identifier_meth
|
222
|
+
|
223
|
+
rows = metadata_dataset.
|
224
|
+
from{pg_constraint.as(:co)}.
|
225
|
+
join(Sequel[:pg_attribute].as(:att), :attrelid=>:conrelid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:conkey])).
|
226
|
+
where(:conrelid=>regclass_oid(table), :contype=>'c').
|
227
|
+
select{[co[:conname].as(:constraint), att[:attname].as(:column), pg_get_constraintdef(co[:oid]).as(:definition)]}
|
228
|
+
|
229
|
+
hash = {}
|
230
|
+
rows.each do |row|
|
231
|
+
constraint = m.call(row[:constraint])
|
232
|
+
if entry = hash[constraint]
|
233
|
+
entry[:columns] << m.call(row[:column])
|
234
|
+
else
|
235
|
+
hash[constraint] = {:definition=>row[:definition], :columns=>[m.call(row[:column])]}
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
hash
|
240
|
+
end
|
241
|
+
|
216
242
|
# Convert the first primary key column in the +table+ from being a serial column to being an identity column.
|
217
243
|
# If the column is already an identity column, assume it was already converted and make no changes.
|
218
244
|
#
|
@@ -396,67 +422,95 @@ module Sequel
|
|
396
422
|
|
397
423
|
# Return full foreign key information using the pg system tables, including
|
398
424
|
# :name, :on_delete, :on_update, and :deferrable entries in the hashes.
|
425
|
+
#
|
426
|
+
# Supports additional options:
|
427
|
+
# :reverse :: Instead of returning foreign keys in the current table, return
|
428
|
+
# foreign keys in other tables that reference the current table.
|
429
|
+
# :schema :: Set to true to have the :table value in the hashes be a qualified
|
430
|
+
# identifier. Set to false to use a separate :schema value with
|
431
|
+
# the related schema. Defaults to whether the given table argument
|
432
|
+
# is a qualified identifier.
|
399
433
|
def foreign_key_list(table, opts=OPTS)
|
400
434
|
m = output_identifier_meth
|
401
435
|
schema, _ = opts.fetch(:schema, schema_and_table(table))
|
402
436
|
oid = regclass_oid(table)
|
437
|
+
reverse = opts[:reverse]
|
438
|
+
|
439
|
+
if reverse
|
440
|
+
ctable = Sequel[:att2]
|
441
|
+
cclass = Sequel[:cl2]
|
442
|
+
rtable = Sequel[:att]
|
443
|
+
rclass = Sequel[:cl]
|
444
|
+
else
|
445
|
+
ctable = Sequel[:att]
|
446
|
+
cclass = Sequel[:cl]
|
447
|
+
rtable = Sequel[:att2]
|
448
|
+
rclass = Sequel[:cl2]
|
449
|
+
end
|
403
450
|
|
404
451
|
if server_version >= 90500
|
405
|
-
cpos = Sequel.expr{array_position(co[:conkey],
|
406
|
-
rpos = Sequel.expr{array_position(co[:confkey],
|
452
|
+
cpos = Sequel.expr{array_position(co[:conkey], ctable[:attnum])}
|
453
|
+
rpos = Sequel.expr{array_position(co[:confkey], rtable[:attnum])}
|
407
454
|
else
|
408
455
|
range = 0...32
|
409
|
-
cpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:conkey], [x]), x]}, 32,
|
410
|
-
rpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:confkey], [x]), x]}, 32,
|
456
|
+
cpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:conkey], [x]), x]}, 32, ctable[:attnum])}
|
457
|
+
rpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:confkey], [x]), x]}, 32, rtable[:attnum])}
|
411
458
|
end
|
412
459
|
|
413
460
|
ds = metadata_dataset.
|
414
461
|
from{pg_constraint.as(:co)}.
|
415
|
-
join(Sequel[:pg_class].as(
|
416
|
-
join(Sequel[:pg_attribute].as(
|
417
|
-
join(Sequel[:pg_class].as(
|
418
|
-
join(Sequel[:pg_attribute].as(
|
462
|
+
join(Sequel[:pg_class].as(cclass), :oid=>:conrelid).
|
463
|
+
join(Sequel[:pg_attribute].as(ctable), :attrelid=>:oid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:conkey])).
|
464
|
+
join(Sequel[:pg_class].as(rclass), :oid=>Sequel[:co][:confrelid]).
|
465
|
+
join(Sequel[:pg_attribute].as(rtable), :attrelid=>:oid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:confkey])).
|
466
|
+
join(Sequel[:pg_namespace].as(:nsp), :oid=>Sequel[:cl2][:relnamespace]).
|
419
467
|
order{[co[:conname], cpos]}.
|
420
468
|
where{{
|
421
469
|
cl[:relkind]=>'r',
|
422
470
|
co[:contype]=>'f',
|
423
471
|
cl[:oid]=>oid,
|
424
472
|
cpos=>rpos
|
425
|
-
|
473
|
+
}}.
|
426
474
|
select{[
|
427
475
|
co[:conname].as(:name),
|
428
|
-
|
476
|
+
ctable[:attname].as(:column),
|
429
477
|
co[:confupdtype].as(:on_update),
|
430
478
|
co[:confdeltype].as(:on_delete),
|
431
479
|
cl2[:relname].as(:table),
|
432
|
-
|
433
|
-
SQL::BooleanExpression.new(:AND, co[:condeferrable], co[:condeferred]).as(:deferrable)
|
480
|
+
rtable[:attname].as(:refcolumn),
|
481
|
+
SQL::BooleanExpression.new(:AND, co[:condeferrable], co[:condeferred]).as(:deferrable),
|
482
|
+
nsp[:nspname].as(:schema)
|
434
483
|
]}
|
435
484
|
|
436
|
-
# If a schema is given, we only search in that schema, and the returned :table
|
437
|
-
# entry is schema qualified as well.
|
438
|
-
if schema
|
439
|
-
ds = ds.join(Sequel[:pg_namespace].as(:nsp2), :oid=>Sequel[:cl2][:relnamespace]).
|
440
|
-
select_append{nsp2[:nspname].as(:schema)}
|
441
|
-
end
|
442
|
-
|
443
485
|
h = {}
|
444
486
|
fklod_map = FOREIGN_KEY_LIST_ON_DELETE_MAP
|
445
487
|
|
446
488
|
ds.each do |row|
|
447
|
-
if
|
489
|
+
if reverse
|
490
|
+
key = [row[:schema], row[:table], row[:name]]
|
491
|
+
else
|
492
|
+
key = row[:name]
|
493
|
+
end
|
494
|
+
|
495
|
+
if r = h[key]
|
448
496
|
r[:columns] << m.call(row[:column])
|
449
497
|
r[:key] << m.call(row[:refcolumn])
|
450
498
|
else
|
451
|
-
h[
|
499
|
+
entry = h[key] = {
|
452
500
|
:name=>m.call(row[:name]),
|
453
501
|
:columns=>[m.call(row[:column])],
|
454
502
|
:key=>[m.call(row[:refcolumn])],
|
455
503
|
:on_update=>fklod_map[row[:on_update]],
|
456
504
|
:on_delete=>fklod_map[row[:on_delete]],
|
457
505
|
:deferrable=>row[:deferrable],
|
458
|
-
:table=>schema ? SQL::QualifiedIdentifier.new(m.call(row[:schema]), m.call(row[:table])) : m.call(row[:table])
|
506
|
+
:table=>schema ? SQL::QualifiedIdentifier.new(m.call(row[:schema]), m.call(row[:table])) : m.call(row[:table]),
|
459
507
|
}
|
508
|
+
|
509
|
+
unless schema
|
510
|
+
# If not combining schema information into the :table entry
|
511
|
+
# include it as a separate entry.
|
512
|
+
entry[:schema] = m.call(row[:schema])
|
513
|
+
end
|
460
514
|
end
|
461
515
|
end
|
462
516
|
|
@@ -494,12 +548,12 @@ module Sequel
|
|
494
548
|
indc[:relkind]=>'i',
|
495
549
|
ind[:indisprimary]=>false,
|
496
550
|
:indexprs=>nil,
|
497
|
-
:indpred=>nil,
|
498
551
|
:indisvalid=>true,
|
499
552
|
tab[:oid]=>oid}}.
|
500
553
|
order(*order).
|
501
554
|
select{[indc[:relname].as(:name), ind[:indisunique].as(:unique), att[:attname].as(:column), con[:condeferrable].as(:deferrable)]}
|
502
555
|
|
556
|
+
ds = ds.where(:indpred=>nil) unless opts[:include_partial]
|
503
557
|
ds = ds.where(:indisready=>true) if server_version >= 80300
|
504
558
|
ds = ds.where(:indislive=>true) if server_version >= 90300
|
505
559
|
|
@@ -809,12 +863,12 @@ module Sequel
|
|
809
863
|
|
810
864
|
VALID_CLIENT_MIN_MESSAGES = %w'DEBUG5 DEBUG4 DEBUG3 DEBUG2 DEBUG1 LOG NOTICE WARNING ERROR FATAL PANIC'.freeze.each(&:freeze)
|
811
865
|
# The SQL queries to execute when starting a new connection.
|
812
|
-
def connection_configuration_sqls
|
866
|
+
def connection_configuration_sqls(opts=@opts)
|
813
867
|
sqls = []
|
814
868
|
|
815
|
-
sqls << "SET standard_conforming_strings = ON" if typecast_value_boolean(
|
869
|
+
sqls << "SET standard_conforming_strings = ON" if typecast_value_boolean(opts.fetch(:force_standard_strings, true))
|
816
870
|
|
817
|
-
cmm =
|
871
|
+
cmm = opts.fetch(:client_min_messages, :warning)
|
818
872
|
if cmm && !cmm.to_s.empty?
|
819
873
|
cmm = cmm.to_s.upcase.strip
|
820
874
|
unless VALID_CLIENT_MIN_MESSAGES.include?(cmm)
|
@@ -823,7 +877,7 @@ module Sequel
|
|
823
877
|
sqls << "SET client_min_messages = '#{cmm.to_s.upcase}'"
|
824
878
|
end
|
825
879
|
|
826
|
-
if search_path =
|
880
|
+
if search_path = opts[:search_path]
|
827
881
|
case search_path
|
828
882
|
when String
|
829
883
|
search_path = search_path.split(",").map(&:strip)
|
@@ -863,6 +917,8 @@ module Sequel
|
|
863
917
|
ExclusionConstraintViolation
|
864
918
|
elsif sqlstate == '40P01'
|
865
919
|
SerializationFailure
|
920
|
+
elsif sqlstate == '55P03'
|
921
|
+
DatabaseLockTimeout
|
866
922
|
else
|
867
923
|
super
|
868
924
|
end
|
@@ -878,6 +934,7 @@ module Sequel
|
|
878
934
|
[/violates not-null constraint/, NotNullConstraintViolation],
|
879
935
|
[/conflicting key value violates exclusion constraint/, ExclusionConstraintViolation],
|
880
936
|
[/could not serialize access/, SerializationFailure],
|
937
|
+
[/could not obtain lock on row in relation/, DatabaseLockTimeout],
|
881
938
|
].freeze
|
882
939
|
def database_error_regexps
|
883
940
|
DATABASE_ERROR_REGEXPS
|
@@ -1577,6 +1634,11 @@ module Sequel
|
|
1577
1634
|
true
|
1578
1635
|
end
|
1579
1636
|
|
1637
|
+
# PostgreSQL supports NOWAIT.
|
1638
|
+
def supports_nowait?
|
1639
|
+
true
|
1640
|
+
end
|
1641
|
+
|
1580
1642
|
# Returning is always supported.
|
1581
1643
|
def supports_returning?(type)
|
1582
1644
|
true
|
@@ -1796,14 +1858,19 @@ module Sequel
|
|
1796
1858
|
# Support FOR SHARE locking when using the :share lock style.
|
1797
1859
|
# Use SKIP LOCKED if skipping locked rows.
|
1798
1860
|
def select_lock_sql(sql)
|
1799
|
-
|
1861
|
+
lock = @opts[:lock]
|
1862
|
+
if lock == :share
|
1800
1863
|
sql << ' FOR SHARE'
|
1801
1864
|
else
|
1802
1865
|
super
|
1803
1866
|
end
|
1804
1867
|
|
1805
|
-
if
|
1806
|
-
|
1868
|
+
if lock
|
1869
|
+
if @opts[:skip_locked]
|
1870
|
+
sql << " SKIP LOCKED"
|
1871
|
+
elsif @opts[:nowait]
|
1872
|
+
sql << " NOWAIT"
|
1873
|
+
end
|
1807
1874
|
end
|
1808
1875
|
end
|
1809
1876
|
|