sequel 5.7.1 → 5.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +53 -1
  3. data/doc/association_basics.rdoc +2 -2
  4. data/doc/migration.rdoc +11 -10
  5. data/doc/postgresql.rdoc +71 -0
  6. data/doc/release_notes/5.8.0.txt +170 -0
  7. data/lib/sequel/adapters/jdbc.rb +6 -1
  8. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -3
  9. data/lib/sequel/adapters/mysql2.rb +2 -1
  10. data/lib/sequel/adapters/postgres.rb +32 -10
  11. data/lib/sequel/adapters/shared/mssql.rb +11 -11
  12. data/lib/sequel/adapters/shared/mysql.rb +51 -6
  13. data/lib/sequel/adapters/shared/oracle.rb +12 -2
  14. data/lib/sequel/adapters/shared/postgres.rb +97 -30
  15. data/lib/sequel/adapters/shared/sqlanywhere.rb +2 -2
  16. data/lib/sequel/adapters/shared/sqlite.rb +6 -1
  17. data/lib/sequel/dataset/features.rb +5 -0
  18. data/lib/sequel/dataset/query.rb +48 -19
  19. data/lib/sequel/exceptions.rb +7 -0
  20. data/lib/sequel/extensions/connection_expiration.rb +8 -3
  21. data/lib/sequel/extensions/pg_enum.rb +28 -5
  22. data/lib/sequel/plugins/association_proxies.rb +16 -4
  23. data/lib/sequel/plugins/error_splitter.rb +16 -11
  24. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +260 -0
  25. data/lib/sequel/plugins/subclasses.rb +1 -1
  26. data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
  27. data/lib/sequel/version.rb +2 -2
  28. data/spec/adapters/mysql_spec.rb +0 -1
  29. data/spec/adapters/postgres_spec.rb +169 -4
  30. data/spec/adapters/sqlite_spec.rb +13 -0
  31. data/spec/core/dataset_spec.rb +21 -0
  32. data/spec/extensions/association_proxies_spec.rb +21 -7
  33. data/spec/extensions/connection_expiration_spec.rb +13 -1
  34. data/spec/extensions/pg_auto_constraint_validations_spec.rb +165 -0
  35. data/spec/extensions/pg_enum_spec.rb +26 -22
  36. data/spec/extensions/tactical_eager_loading_spec.rb +11 -0
  37. data/spec/integration/dataset_test.rb +30 -6
  38. data/spec/integration/plugin_test.rb +2 -2
  39. 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 << if for_update
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 << "READPAST"
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
- type == :select && db.mariadb? && db.server_version >= 100200
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.mariadb? && db.server_version >= 100200
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] == :share ? (sql << ' LOCK IN SHARE MODE') : super
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[:skip_locked]
626
- sql << " SKIP LOCKED"
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], att[:attnum])}
406
- rpos = Sequel.expr{array_position(co[:confkey], att2[:attnum])}
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, att[:attnum])}
410
- rpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:confkey], [x]), x]}, 32, att2[:attnum])}
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(:cl), :oid=>:conrelid).
416
- join(Sequel[:pg_attribute].as(:att), :attrelid=>:oid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:conkey])).
417
- join(Sequel[:pg_class].as(:cl2), :oid=>Sequel[:co][:confrelid]).
418
- join(Sequel[:pg_attribute].as(:att2), :attrelid=>:oid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:confkey])).
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
- att[:attname].as(:column),
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
- att2[:attname].as(:refcolumn),
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 r = h[row[:name]]
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[row[:name]] = {
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(@opts.fetch(:force_standard_strings, true))
869
+ sqls << "SET standard_conforming_strings = ON" if typecast_value_boolean(opts.fetch(:force_standard_strings, true))
816
870
 
817
- cmm = @opts.fetch(:client_min_messages, :warning)
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 = @opts[: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
- if @opts[:lock] == :share
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 @opts[:skip_locked]
1806
- sql << " SKIP LOCKED"
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