sequel 5.7.1 → 5.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|