sequel 5.106.0 → 5.109.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/bin/sequel +5 -5
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/amalgalite.rb +34 -8
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -1
- data/lib/sequel/adapters/jdbc/mssql.rb +28 -5
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +14 -3
- data/lib/sequel/adapters/jdbc.rb +4 -3
- data/lib/sequel/adapters/mock.rb +1 -1
- data/lib/sequel/adapters/mysql.rb +7 -2
- data/lib/sequel/adapters/mysql2.rb +5 -4
- data/lib/sequel/adapters/postgres.rb +42 -39
- data/lib/sequel/adapters/shared/db2.rb +5 -2
- data/lib/sequel/adapters/shared/mssql.rb +11 -5
- data/lib/sequel/adapters/shared/mysql.rb +2 -2
- data/lib/sequel/adapters/shared/postgres.rb +80 -92
- data/lib/sequel/adapters/shared/sqlanywhere.rb +0 -32
- data/lib/sequel/adapters/shared/sqlite.rb +8 -7
- data/lib/sequel/adapters/sqlite.rb +13 -9
- data/lib/sequel/adapters/trilogy.rb +2 -1
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +11 -1
- data/lib/sequel/connection_pool/sharded_single.rb +1 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +7 -5
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +3 -3
- data/lib/sequel/connection_pool/threaded.rb +9 -7
- data/lib/sequel/connection_pool/timed_queue.rb +2 -2
- data/lib/sequel/connection_pool.rb +3 -3
- data/lib/sequel/core.rb +44 -24
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/features.rb +1 -1
- data/lib/sequel/database/misc.rb +6 -11
- data/lib/sequel/database/query.rb +2 -2
- data/lib/sequel/database/schema_generator.rb +7 -5
- data/lib/sequel/database/schema_methods.rb +2 -2
- data/lib/sequel/database/transactions.rb +5 -7
- data/lib/sequel/dataset/actions.rb +2 -2
- data/lib/sequel/dataset/features.rb +4 -4
- data/lib/sequel/dataset/graph.rb +1 -1
- data/lib/sequel/dataset/misc.rb +3 -3
- data/lib/sequel/dataset/prepared_statements.rb +2 -2
- data/lib/sequel/dataset/query.rb +8 -8
- data/lib/sequel/dataset/sql.rb +32 -13
- data/lib/sequel/dataset.rb +2 -2
- data/lib/sequel/deprecated.rb +2 -2
- data/lib/sequel/exceptions.rb +2 -2
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/async_thread_pool.rb +3 -3
- data/lib/sequel/extensions/auto_cast_date_and_time.rb +2 -2
- data/lib/sequel/extensions/blank.rb +2 -2
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/core_refinements.rb +7 -10
- data/lib/sequel/extensions/date_arithmetic.rb +1 -1
- data/lib/sequel/extensions/datetime_parse_to_time.rb +2 -2
- data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -3
- data/lib/sequel/extensions/graph_each.rb +1 -1
- data/lib/sequel/extensions/index_caching.rb +1 -1
- data/lib/sequel/extensions/inflector.rb +5 -5
- data/lib/sequel/extensions/is_distinct_from.rb +2 -2
- data/lib/sequel/extensions/lit_require_frozen.rb +20 -4
- data/lib/sequel/extensions/migration.rb +21 -7
- data/lib/sequel/extensions/named_timezones.rb +9 -9
- data/lib/sequel/extensions/pg_array.rb +10 -8
- data/lib/sequel/extensions/pg_array_ops.rb +69 -14
- data/lib/sequel/extensions/pg_auto_parameterize.rb +2 -2
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +3 -3
- data/lib/sequel/extensions/pg_enum.rb +2 -2
- data/lib/sequel/extensions/pg_extended_date_support.rb +5 -5
- data/lib/sequel/extensions/pg_extended_integer_support.rb +1 -1
- data/lib/sequel/extensions/pg_hstore.rb +2 -2
- data/lib/sequel/extensions/pg_hstore_ops.rb +5 -5
- data/lib/sequel/extensions/pg_inet.rb +2 -2
- data/lib/sequel/extensions/pg_inet_ops.rb +2 -2
- data/lib/sequel/extensions/pg_interval.rb +6 -6
- data/lib/sequel/extensions/pg_json.rb +4 -4
- data/lib/sequel/extensions/pg_json_ops.rb +15 -13
- data/lib/sequel/extensions/pg_range.rb +6 -6
- data/lib/sequel/extensions/pg_range_ops.rb +7 -7
- data/lib/sequel/extensions/pg_row.rb +4 -4
- data/lib/sequel/extensions/pg_row_ops.rb +6 -6
- data/lib/sequel/extensions/provenance.rb +2 -2
- data/lib/sequel/extensions/query.rb +2 -2
- data/lib/sequel/extensions/s.rb +6 -10
- data/lib/sequel/extensions/schema_dumper.rb +10 -6
- data/lib/sequel/extensions/sequel_4_dataset_methods.rb +2 -0
- data/lib/sequel/extensions/sql_comments.rb +1 -1
- data/lib/sequel/extensions/sql_log_normalizer.rb +1 -1
- data/lib/sequel/extensions/sqlite_json_ops.rb +2 -2
- data/lib/sequel/extensions/string_agg.rb +5 -5
- data/lib/sequel/extensions/symbol_aref.rb +12 -32
- data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -5
- data/lib/sequel/extensions/symbol_as.rb +1 -2
- data/lib/sequel/extensions/symbol_as_refinement.rb +1 -5
- data/lib/sequel/extensions/transaction_connection_validator.rb +1 -1
- data/lib/sequel/model/associations.rb +17 -17
- data/lib/sequel/model/base.rb +18 -15
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model/plugins.rb +2 -2
- data/lib/sequel/model.rb +2 -2
- data/lib/sequel/plugins/association_pks.rb +1 -1
- data/lib/sequel/plugins/association_proxies.rb +4 -4
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +2 -0
- data/lib/sequel/plugins/caching.rb +28 -3
- data/lib/sequel/plugins/class_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/column_encryption.rb +10 -10
- data/lib/sequel/plugins/concurrent_eager_loading.rb +2 -2
- data/lib/sequel/plugins/csv_serializer.rb +9 -20
- data/lib/sequel/plugins/deprecated_associations.rb +2 -2
- data/lib/sequel/plugins/eager_each.rb +1 -1
- data/lib/sequel/plugins/finder.rb +1 -1
- data/lib/sequel/plugins/forbid_lazy_load.rb +3 -3
- data/lib/sequel/plugins/insert_conflict.rb +1 -1
- data/lib/sequel/plugins/insert_returning_select.rb +1 -1
- data/lib/sequel/plugins/instance_filters.rb +8 -0
- data/lib/sequel/plugins/instance_hooks.rb +19 -0
- data/lib/sequel/plugins/json_serializer.rb +4 -4
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +9 -0
- data/lib/sequel/plugins/optimistic_locking.rb +12 -2
- data/lib/sequel/plugins/optimistic_locking_base.rb +14 -0
- data/lib/sequel/plugins/pg_array_associations.rb +4 -4
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +3 -3
- data/lib/sequel/plugins/pg_eager_any_typed_array.rb +2 -2
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +11 -2
- data/lib/sequel/plugins/prepared_statements.rb +2 -2
- data/lib/sequel/plugins/select_on_skipped_update.rb +63 -0
- data/lib/sequel/plugins/serialization.rb +1 -1
- data/lib/sequel/plugins/sharding.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +21 -3
- data/lib/sequel/plugins/skip_saving_columns.rb +2 -2
- data/lib/sequel/plugins/split_values.rb +1 -1
- data/lib/sequel/plugins/sql_comments.rb +8 -8
- data/lib/sequel/plugins/subclasses.rb +6 -6
- data/lib/sequel/plugins/subset_conditions.rb +5 -16
- data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
- data/lib/sequel/plugins/throw_failures.rb +3 -3
- data/lib/sequel/plugins/unused_associations.rb +5 -5
- data/lib/sequel/plugins/validate_associated.rb +7 -1
- data/lib/sequel/plugins/validate_associated_context.rb +52 -0
- data/lib/sequel/plugins/validation_helpers.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +2 -0
- data/lib/sequel/sql.rb +120 -116
- data/lib/sequel/version.rb +1 -1
- metadata +5 -3
|
@@ -42,7 +42,7 @@ module Sequel
|
|
|
42
42
|
#
|
|
43
43
|
# :result :: The result code of the stored procedure
|
|
44
44
|
# :numrows :: The number of rows affected by the stored procedure
|
|
45
|
-
# output params :: Values for any output
|
|
45
|
+
# output params :: Values for any output parameters, using the name given for the output parameter
|
|
46
46
|
#
|
|
47
47
|
# Because Sequel datasets only support a single result set per query, and retrieving
|
|
48
48
|
# the result code and number of rows requires a query, this does not support
|
|
@@ -400,6 +400,9 @@ module Sequel
|
|
|
400
400
|
# Error if a string is given.
|
|
401
401
|
def create_table_as(name, ds, options)
|
|
402
402
|
raise(Error, "must provide dataset instance as value of create_table :as option on MSSQL") unless ds.is_a?(Sequel::Dataset)
|
|
403
|
+
if options[:temp]
|
|
404
|
+
name = create_table_temp_table_name_sql(name, options)
|
|
405
|
+
end
|
|
403
406
|
run(ds.into(name).sql.freeze)
|
|
404
407
|
end
|
|
405
408
|
|
|
@@ -672,14 +675,17 @@ module Sequel
|
|
|
672
675
|
end
|
|
673
676
|
end
|
|
674
677
|
|
|
675
|
-
# MSSQL treats [] as a metacharacter in LIKE
|
|
678
|
+
# MSSQL treats [] as a metacharacter in LIKE expressions.
|
|
676
679
|
def escape_like(string)
|
|
677
680
|
string.gsub(/[\\%_\[\]]/){|m| "\\#{m}"}
|
|
678
681
|
end
|
|
679
682
|
|
|
680
683
|
# MSSQL uses the CONTAINS keyword for full text search
|
|
681
684
|
def full_text_search(cols, terms, opts = OPTS)
|
|
682
|
-
|
|
685
|
+
case terms
|
|
686
|
+
when Array, Set
|
|
687
|
+
terms = Sequel.array_or_set_join(terms.map{|term| "\"#{term.to_s.gsub('"', '""')}\""}, " OR ")
|
|
688
|
+
end
|
|
683
689
|
where(Sequel.lit("CONTAINS (?, ?)", cols, terms))
|
|
684
690
|
end
|
|
685
691
|
|
|
@@ -941,7 +947,7 @@ module Sequel
|
|
|
941
947
|
# Allow update and delete for unordered, limited datasets only.
|
|
942
948
|
def check_not_limited!(type)
|
|
943
949
|
return if @opts[:skip_limit_check] && type != :truncate
|
|
944
|
-
raise Sequel::InvalidOperation, "Dataset##{type} not
|
|
950
|
+
raise Sequel::InvalidOperation, "Dataset##{type} not supported on ordered, limited datasets" if opts[:order] && opts[:limit]
|
|
945
951
|
super if type == :truncate || @opts[:offset]
|
|
946
952
|
end
|
|
947
953
|
|
|
@@ -1040,7 +1046,7 @@ module Sequel
|
|
|
1040
1046
|
end
|
|
1041
1047
|
end
|
|
1042
1048
|
|
|
1043
|
-
# MSSQL uses a literal
|
|
1049
|
+
# MSSQL uses a literal hexadecimal number for blob strings
|
|
1044
1050
|
def literal_blob_append(sql, v)
|
|
1045
1051
|
sql << '0x' << v.unpack("H*").first
|
|
1046
1052
|
end
|
|
@@ -381,7 +381,7 @@ module Sequel
|
|
|
381
381
|
'AUTO_INCREMENT'
|
|
382
382
|
end
|
|
383
383
|
|
|
384
|
-
# MySQL needs to set transaction isolation before
|
|
384
|
+
# MySQL needs to set transaction isolation before beginning a transaction
|
|
385
385
|
def begin_new_transaction(conn, opts)
|
|
386
386
|
set_transaction_isolation(conn, opts)
|
|
387
387
|
log_connection_execute(conn, begin_transaction_sql)
|
|
@@ -937,7 +937,7 @@ module Sequel
|
|
|
937
937
|
end
|
|
938
938
|
|
|
939
939
|
# Check the database setting for whether fractional timestamps
|
|
940
|
-
# are
|
|
940
|
+
# are supported.
|
|
941
941
|
def supports_timestamp_usecs?
|
|
942
942
|
db.supports_timestamp_usecs?
|
|
943
943
|
end
|
|
@@ -204,12 +204,12 @@ module Sequel
|
|
|
204
204
|
@in = v
|
|
205
205
|
end
|
|
206
206
|
|
|
207
|
-
# Assumes hash partitioning, sets the modulus for this
|
|
207
|
+
# Assumes hash partitioning, sets the modulus for this partition.
|
|
208
208
|
def modulus(v)
|
|
209
209
|
@modulus = v
|
|
210
210
|
end
|
|
211
211
|
|
|
212
|
-
# Assumes hash partitioning, sets the remainder for this
|
|
212
|
+
# Assumes hash partitioning, sets the remainder for this partition.
|
|
213
213
|
def remainder(v)
|
|
214
214
|
@remainder = v
|
|
215
215
|
end
|
|
@@ -346,7 +346,7 @@ module Sequel
|
|
|
346
346
|
# Keys are CHECK constraint name symbols. Values are hashes with the following keys:
|
|
347
347
|
# :definition :: An SQL fragment for the definition of the constraint
|
|
348
348
|
# :columns :: An array of column symbols for the columns referenced in the constraint,
|
|
349
|
-
# can be an empty array if the database cannot
|
|
349
|
+
# can be an empty array if the database cannot determine the column symbols.
|
|
350
350
|
def check_constraints(table)
|
|
351
351
|
m = output_identifier_meth
|
|
352
352
|
|
|
@@ -772,12 +772,12 @@ module Sequel
|
|
|
772
772
|
seq_ds = metadata_dataset.from(:pg_sequence).where(:seqrelid=>regclass_oid(LiteralString.new(seq.freeze)))
|
|
773
773
|
increment_by = :seqincrement
|
|
774
774
|
min_value = :seqmin
|
|
775
|
-
# :
|
|
775
|
+
# simplecov:disable
|
|
776
776
|
else
|
|
777
777
|
seq_ds = metadata_dataset.from(LiteralString.new(seq))
|
|
778
778
|
increment_by = :increment_by
|
|
779
779
|
min_value = :min_value
|
|
780
|
-
# :
|
|
780
|
+
# simplecov:enable
|
|
781
781
|
end
|
|
782
782
|
|
|
783
783
|
get{setval(seq, db[table].select(coalesce(max(pk)+seq_ds.select(increment_by), seq_ds.select(min_value))), false)}
|
|
@@ -790,9 +790,9 @@ module Sequel
|
|
|
790
790
|
# PostgreSQL uses SERIAL psuedo-type instead of AUTOINCREMENT for
|
|
791
791
|
# managing incrementing primary keys.
|
|
792
792
|
def serial_primary_key_options
|
|
793
|
-
# :
|
|
793
|
+
# simplecov:disable
|
|
794
794
|
auto_increment_key = server_version >= 100002 ? :identity : :serial
|
|
795
|
-
# :
|
|
795
|
+
# simplecov:enable
|
|
796
796
|
{:primary_key => true, auto_increment_key => true, :type=>Integer}
|
|
797
797
|
end
|
|
798
798
|
|
|
@@ -979,12 +979,12 @@ module Sequel
|
|
|
979
979
|
if server_version >= 90500
|
|
980
980
|
cpos = Sequel.expr{array_position(co[:conkey], ctable[:attnum])}
|
|
981
981
|
rpos = Sequel.expr{array_position(co[:confkey], rtable[:attnum])}
|
|
982
|
-
# :
|
|
982
|
+
# simplecov:disable
|
|
983
983
|
else
|
|
984
984
|
range = 0...32
|
|
985
985
|
cpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:conkey], [x]), x]}, 32, ctable[:attnum])}
|
|
986
986
|
rpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:confkey], [x]), x]}, 32, rtable[:attnum])}
|
|
987
|
-
# :
|
|
987
|
+
# simplecov:enable
|
|
988
988
|
end
|
|
989
989
|
|
|
990
990
|
ds = metadata_dataset.
|
|
@@ -1021,19 +1021,19 @@ module Sequel
|
|
|
1021
1021
|
def _add_validated_enforced_constraint_columns(ds)
|
|
1022
1022
|
validated_cond = if server_version >= 90100
|
|
1023
1023
|
Sequel[:convalidated]
|
|
1024
|
-
# :
|
|
1024
|
+
# simplecov:disable
|
|
1025
1025
|
else
|
|
1026
1026
|
Sequel.cast(true, TrueClass)
|
|
1027
|
-
# :
|
|
1027
|
+
# simplecov:enable
|
|
1028
1028
|
end
|
|
1029
1029
|
ds = ds.select_append(validated_cond.as(:validated))
|
|
1030
1030
|
|
|
1031
1031
|
enforced_cond = if server_version >= 180000
|
|
1032
1032
|
Sequel[:conenforced]
|
|
1033
|
-
# :
|
|
1033
|
+
# simplecov:disable
|
|
1034
1034
|
else
|
|
1035
1035
|
Sequel.cast(true, TrueClass)
|
|
1036
|
-
# :
|
|
1036
|
+
# simplecov:enable
|
|
1037
1037
|
end
|
|
1038
1038
|
ds = ds.select_append(enforced_cond.as(:enforced))
|
|
1039
1039
|
|
|
@@ -1045,11 +1045,11 @@ module Sequel
|
|
|
1045
1045
|
@_indexes_ds ||= begin
|
|
1046
1046
|
if server_version >= 90500
|
|
1047
1047
|
order = [Sequel[:indc][:relname], Sequel.function(:array_position, Sequel[:ind][:indkey], Sequel[:att][:attnum])]
|
|
1048
|
-
# :
|
|
1048
|
+
# simplecov:disable
|
|
1049
1049
|
else
|
|
1050
1050
|
range = 0...32
|
|
1051
1051
|
order = [Sequel[:indc][:relname], SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(Sequel[:ind][:indkey], [x]), x]}, 32, Sequel[:att][:attnum])]
|
|
1052
|
-
# :
|
|
1052
|
+
# simplecov:enable
|
|
1053
1053
|
end
|
|
1054
1054
|
|
|
1055
1055
|
attnums = SQL::Function.new(:ANY, Sequel[:ind][:indkey])
|
|
@@ -1067,10 +1067,10 @@ module Sequel
|
|
|
1067
1067
|
order(*order).
|
|
1068
1068
|
select{[indc[:relname].as(:name), ind[:indisunique].as(:unique), att[:attname].as(:column), con[:condeferrable].as(:deferrable)]}
|
|
1069
1069
|
|
|
1070
|
-
# :
|
|
1070
|
+
# simplecov:disable
|
|
1071
1071
|
ds = ds.where(:indisready=>true) if server_version >= 80300
|
|
1072
1072
|
ds = ds.where(:indislive=>true) if server_version >= 90300
|
|
1073
|
-
# :
|
|
1073
|
+
# simplecov:enable
|
|
1074
1074
|
|
|
1075
1075
|
ds
|
|
1076
1076
|
end
|
|
@@ -1163,14 +1163,14 @@ module Sequel
|
|
|
1163
1163
|
where{pg_attribute[:attnum] > 0}.
|
|
1164
1164
|
order{pg_attribute[:attnum]}
|
|
1165
1165
|
|
|
1166
|
-
# :
|
|
1166
|
+
# simplecov:disable
|
|
1167
1167
|
if server_version > 100000
|
|
1168
|
-
# :
|
|
1168
|
+
# simplecov:enable
|
|
1169
1169
|
ds = ds.select_append{pg_attribute[:attidentity]}
|
|
1170
1170
|
|
|
1171
|
-
# :
|
|
1171
|
+
# simplecov:disable
|
|
1172
1172
|
if server_version > 120000
|
|
1173
|
-
# :
|
|
1173
|
+
# simplecov:enable
|
|
1174
1174
|
ds = ds.select_append{Sequel.~(pg_attribute[:attgenerated]=>'').as(:generated)}
|
|
1175
1175
|
end
|
|
1176
1176
|
end
|
|
@@ -1261,7 +1261,7 @@ module Sequel
|
|
|
1261
1261
|
|
|
1262
1262
|
# If the :synchronous option is given and non-nil, set synchronous_commit
|
|
1263
1263
|
# appropriately. Valid values for the :synchronous option are true,
|
|
1264
|
-
# :on, false, :off, :local, and :remote_write.
|
|
1264
|
+
# :on, false, :off, :local, :remote_apply, and :remote_write.
|
|
1265
1265
|
def begin_new_transaction(conn, opts)
|
|
1266
1266
|
super
|
|
1267
1267
|
if opts.has_key?(:synchronous)
|
|
@@ -1272,6 +1272,12 @@ module Sequel
|
|
|
1272
1272
|
sync = :off
|
|
1273
1273
|
when nil
|
|
1274
1274
|
return
|
|
1275
|
+
when :on, :off, :local, :remote_apply, :remote_write
|
|
1276
|
+
nil
|
|
1277
|
+
else
|
|
1278
|
+
# SEQUEL6: raise
|
|
1279
|
+
Sequel::Deprecation.deprecate("Unsupported :synchronous option given to Database#transaction: #{sync.inspect}, this will raise an error in Sequel 6.")
|
|
1280
|
+
return
|
|
1275
1281
|
end
|
|
1276
1282
|
|
|
1277
1283
|
log_connection_execute(conn, "SET LOCAL synchronous_commit = #{sync}")
|
|
@@ -1526,8 +1532,14 @@ module Sequel
|
|
|
1526
1532
|
if opts[:options] || opts[:format]
|
|
1527
1533
|
options = String.new
|
|
1528
1534
|
options << " ("
|
|
1529
|
-
|
|
1530
|
-
|
|
1535
|
+
if format = opts[:format]
|
|
1536
|
+
sql_format = format.to_s.downcase
|
|
1537
|
+
unless %w[text csv json binary].freeze.include?(sql_format)
|
|
1538
|
+
raise Error, "unsupported COPY TO format: #{format.inspect}"
|
|
1539
|
+
end
|
|
1540
|
+
options << "FORMAT #{format}"
|
|
1541
|
+
end
|
|
1542
|
+
options << "#{', ' if format}#{opts[:options]}" if opts[:options]
|
|
1531
1543
|
options << ')'
|
|
1532
1544
|
end
|
|
1533
1545
|
table = if table.is_a?(::Sequel::Dataset)
|
|
@@ -1623,7 +1635,7 @@ module Sequel
|
|
|
1623
1635
|
"#{super}#{create_table_suffix_sql(name, options)}"
|
|
1624
1636
|
end
|
|
1625
1637
|
|
|
1626
|
-
# Handle various
|
|
1638
|
+
# Handle various PostgreSQL specific table extensions such as inheritance,
|
|
1627
1639
|
# partitioning, tablespaces, and foreign tables.
|
|
1628
1640
|
def create_table_suffix_sql(name, options)
|
|
1629
1641
|
sql = String.new
|
|
@@ -1922,9 +1934,9 @@ module Sequel
|
|
|
1922
1934
|
row[:auto_increment] = !!(row[:default] =~ /\A(?:nextval)/i) || identity == 'a' || identity == 'd'
|
|
1923
1935
|
end
|
|
1924
1936
|
|
|
1925
|
-
# :
|
|
1937
|
+
# simplecov:disable
|
|
1926
1938
|
if server_version >= 90600
|
|
1927
|
-
# :
|
|
1939
|
+
# simplecov:enable
|
|
1928
1940
|
case row[:oid]
|
|
1929
1941
|
when 1082
|
|
1930
1942
|
row[:min_value] = MIN_DATE
|
|
@@ -2013,9 +2025,9 @@ module Sequel
|
|
|
2013
2025
|
|
|
2014
2026
|
# PostgreSQL 9.4+ supports views with check option.
|
|
2015
2027
|
def view_with_check_option_support
|
|
2016
|
-
# :
|
|
2028
|
+
# simplecov:disable
|
|
2017
2029
|
:local if server_version >= 90400
|
|
2018
|
-
# :
|
|
2030
|
+
# simplecov:enable
|
|
2019
2031
|
end
|
|
2020
2032
|
end
|
|
2021
2033
|
|
|
@@ -2118,12 +2130,12 @@ module Sequel
|
|
|
2118
2130
|
rows[0]
|
|
2119
2131
|
elsif rows.all?{|row| String === row}
|
|
2120
2132
|
rows.join("\r\n")
|
|
2121
|
-
# :
|
|
2133
|
+
# simplecov:disable
|
|
2122
2134
|
else
|
|
2123
2135
|
# This branch is unreachable in tests, but it seems better to just return
|
|
2124
2136
|
# all rows than throw in error if this case actually happens.
|
|
2125
2137
|
rows
|
|
2126
|
-
# :
|
|
2138
|
+
# simplecov:enable
|
|
2127
2139
|
end
|
|
2128
2140
|
end
|
|
2129
2141
|
|
|
@@ -2133,26 +2145,6 @@ module Sequel
|
|
|
2133
2145
|
cached_lock_style_dataset(:_for_key_share_ds, :key_share)
|
|
2134
2146
|
end
|
|
2135
2147
|
|
|
2136
|
-
# Set FOR PORTION OF clause for UPDATE and DELETE statements.
|
|
2137
|
-
# The first argument is the range or multirange column. If two arguments
|
|
2138
|
-
# are provided, the second argument is an expression with the same
|
|
2139
|
-
# database type as the first argument. If three arguments are provided,
|
|
2140
|
-
# the second specifies the inclusive start of the portion to update and the third
|
|
2141
|
-
# specifies the exclusive end of portion to update. When using the three argument
|
|
2142
|
-
# form, nil can be provided as the second or third argument to have the start or
|
|
2143
|
-
# end of the portion be unbounded. Supported on PostgreSQL 19+.
|
|
2144
|
-
# Example:
|
|
2145
|
-
#
|
|
2146
|
-
# DB[:t].for_portion_of(:rc, Sequel.function(:int4range, 1, 2)).update(c: 3)
|
|
2147
|
-
# # UPDATE t FOR PORTION OF rc (int4range(1, 2)) SET c = 3
|
|
2148
|
-
#
|
|
2149
|
-
# DB[:t].for_portion_of(:rc, 1, 2).update(c: 3)
|
|
2150
|
-
# # UPDATE t FOR PORTION OF rc FROM 1 TO 2 SET c = 3
|
|
2151
|
-
def for_portion_of(column, range, to=(arg_not_given=true))
|
|
2152
|
-
range = [range, to].freeze unless arg_not_given
|
|
2153
|
-
clone(:for_portion_of => [column, range].freeze)
|
|
2154
|
-
end
|
|
2155
|
-
|
|
2156
2148
|
# Return a cloned dataset which will use FOR NO KEY UPDATE to lock returned rows.
|
|
2157
2149
|
# This is generally a better choice than using for_update on PostgreSQL, unless
|
|
2158
2150
|
# you will be deleting the row or modifying a key column. Supported on PostgreSQL 9.3+.
|
|
@@ -2245,8 +2237,11 @@ module Sequel
|
|
|
2245
2237
|
# Handle uniqueness violations when inserting, by updating the conflicting row, using
|
|
2246
2238
|
# ON CONFLICT. With no options, uses ON CONFLICT DO NOTHING. Options:
|
|
2247
2239
|
# :conflict_where :: The index filter, when using a partial index to determine uniqueness.
|
|
2248
|
-
# :constraint :: An explicit constraint name, has
|
|
2240
|
+
# :constraint :: An explicit constraint name, has precedence over :target.
|
|
2249
2241
|
# :target :: The column name or expression to handle uniqueness violations on.
|
|
2242
|
+
# :select :: Use ON CONFLICT DO SELECT. This will use the dataset's lock style.
|
|
2243
|
+
# You must use #returning on this dataset when using this option.
|
|
2244
|
+
# :select_where :: A WHERE condition to use for the select.
|
|
2250
2245
|
# :update :: A hash of columns and values to set. Uses ON CONFLICT DO UPDATE.
|
|
2251
2246
|
# :update_where :: A WHERE condition to use for the update.
|
|
2252
2247
|
#
|
|
@@ -2277,7 +2272,21 @@ module Sequel
|
|
|
2277
2272
|
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
2278
2273
|
# # ON CONFLICT ON CONSTRAINT table_a_uidx
|
|
2279
2274
|
# # DO UPDATE SET b = excluded.b WHERE (table.status_id = 1)
|
|
2275
|
+
#
|
|
2276
|
+
# DB[:table].returning(:a).insert_conflict(target: :a, select: true).insert(a: 1, b: 2)
|
|
2277
|
+
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
2278
|
+
# # ON CONFLICT (a) DO SELECT RETURNING a
|
|
2279
|
+
#
|
|
2280
|
+
# DB[:table].returning(:a).for_update.
|
|
2281
|
+
# insert_conflict(target: :a, select: true, select_where: {Sequel[:excluded][:b] => 3}).
|
|
2282
|
+
# insert(a: 1, b: 2)
|
|
2283
|
+
# # INSERT INTO TABLE (a, b) VALUES (1, 2)
|
|
2284
|
+
# # ON CONFLICT (a) DO SELECT FOR UPDATE WHERE (excluded.b = 3) RETURNING a
|
|
2280
2285
|
def insert_conflict(opts=OPTS)
|
|
2286
|
+
if opts[:select] && opts[:update]
|
|
2287
|
+
raise Error, "Cannot provide both :select and :update options to insert_conflict"
|
|
2288
|
+
end
|
|
2289
|
+
|
|
2281
2290
|
clone(:insert_conflict => opts)
|
|
2282
2291
|
end
|
|
2283
2292
|
|
|
@@ -2518,14 +2527,14 @@ module Sequel
|
|
|
2518
2527
|
server_version >= 90500
|
|
2519
2528
|
end
|
|
2520
2529
|
|
|
2521
|
-
# :
|
|
2530
|
+
# simplecov:disable
|
|
2522
2531
|
|
|
2523
2532
|
# PostgreSQL supports timezones in literal timestamps
|
|
2524
2533
|
def supports_timestamp_timezones?
|
|
2525
2534
|
# SEQUEL6: Remove
|
|
2526
2535
|
true
|
|
2527
2536
|
end
|
|
2528
|
-
# :
|
|
2537
|
+
# simplecov:enable
|
|
2529
2538
|
|
|
2530
2539
|
# PostgreSQL 8.4+ supports WINDOW clause.
|
|
2531
2540
|
def supports_window_clause?
|
|
@@ -2640,7 +2649,7 @@ module Sequel
|
|
|
2640
2649
|
end
|
|
2641
2650
|
|
|
2642
2651
|
# Use from_self for aggregate dataset using VALUES.
|
|
2643
|
-
def
|
|
2652
|
+
def aggregate_dataset_use_from_self?
|
|
2644
2653
|
super || @opts[:values]
|
|
2645
2654
|
end
|
|
2646
2655
|
|
|
@@ -2655,11 +2664,10 @@ module Sequel
|
|
|
2655
2664
|
"'%Y-%m-%d %H:%M:%S.%6N%z'"
|
|
2656
2665
|
end
|
|
2657
2666
|
|
|
2658
|
-
# Only include the primary table in the main delete clause
|
|
2659
|
-
# Support FOR PORTION OF.
|
|
2667
|
+
# Only include the primary table in the main delete clause
|
|
2660
2668
|
def delete_from_sql(sql)
|
|
2661
2669
|
sql << ' FROM '
|
|
2662
|
-
|
|
2670
|
+
source_list_append(sql, @opts[:from][0..0])
|
|
2663
2671
|
end
|
|
2664
2672
|
|
|
2665
2673
|
# Use USING to specify additional tables in a delete query
|
|
@@ -2702,7 +2710,7 @@ module Sequel
|
|
|
2702
2710
|
origin = String.new
|
|
2703
2711
|
origin << 'EXPLAIN '
|
|
2704
2712
|
|
|
2705
|
-
# :
|
|
2713
|
+
# simplecov:disable
|
|
2706
2714
|
if server_version < 90000
|
|
2707
2715
|
if opts[:analyze]
|
|
2708
2716
|
origin << 'ANALYZE '
|
|
@@ -2710,7 +2718,7 @@ module Sequel
|
|
|
2710
2718
|
|
|
2711
2719
|
return origin
|
|
2712
2720
|
end
|
|
2713
|
-
# :
|
|
2721
|
+
# simplecov:enable
|
|
2714
2722
|
|
|
2715
2723
|
comma = nil
|
|
2716
2724
|
paren = "("
|
|
@@ -2744,32 +2752,6 @@ module Sequel
|
|
|
2744
2752
|
origin
|
|
2745
2753
|
end
|
|
2746
2754
|
|
|
2747
|
-
# Add FOR PORTION OF SQL if the dataset uses it.
|
|
2748
|
-
def table_for_portion_of_sql_append(sql)
|
|
2749
|
-
fpo_column, fpo_range = @opts[:for_portion_of]
|
|
2750
|
-
if fpo_column
|
|
2751
|
-
table, aliaz = split_alias(@opts[:from].first)
|
|
2752
|
-
source_list_append(sql, [table])
|
|
2753
|
-
sql << ' FOR PORTION OF '
|
|
2754
|
-
literal_append(sql, fpo_column)
|
|
2755
|
-
|
|
2756
|
-
if fpo_range.is_a?(Array)
|
|
2757
|
-
fpo_start, fpo_end = fpo_range
|
|
2758
|
-
sql << ' FROM '
|
|
2759
|
-
literal_append(sql, fpo_start)
|
|
2760
|
-
sql << ' TO '
|
|
2761
|
-
literal_append(sql, fpo_end)
|
|
2762
|
-
else
|
|
2763
|
-
sql << ' ('
|
|
2764
|
-
literal_append(sql, fpo_range)
|
|
2765
|
-
sql << ')'
|
|
2766
|
-
end
|
|
2767
|
-
as_sql_append(sql, aliaz) if aliaz
|
|
2768
|
-
else
|
|
2769
|
-
source_list_append(sql, @opts[:from][0..0])
|
|
2770
|
-
end
|
|
2771
|
-
end
|
|
2772
|
-
|
|
2773
2755
|
# Add ON CONFLICT clause if it should be used
|
|
2774
2756
|
def insert_conflict_sql(sql)
|
|
2775
2757
|
if opts = @opts[:insert_conflict]
|
|
@@ -2790,13 +2772,19 @@ module Sequel
|
|
|
2790
2772
|
if values = opts[:update]
|
|
2791
2773
|
sql << " DO UPDATE SET "
|
|
2792
2774
|
update_sql_values_hash(sql, values)
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2775
|
+
where = opts[:update_where]
|
|
2776
|
+
elsif opts[:select]
|
|
2777
|
+
sql << " DO SELECT"
|
|
2778
|
+
select_lock_sql(sql)
|
|
2779
|
+
where = opts[:select_where]
|
|
2797
2780
|
else
|
|
2798
2781
|
sql << " DO NOTHING"
|
|
2799
2782
|
end
|
|
2783
|
+
|
|
2784
|
+
if where
|
|
2785
|
+
sql << " WHERE "
|
|
2786
|
+
literal_append(sql, where)
|
|
2787
|
+
end
|
|
2800
2788
|
end
|
|
2801
2789
|
end
|
|
2802
2790
|
|
|
@@ -3059,10 +3047,10 @@ module Sequel
|
|
|
3059
3047
|
join_from_sql(:FROM, sql)
|
|
3060
3048
|
end
|
|
3061
3049
|
|
|
3062
|
-
#
|
|
3050
|
+
# Only include the primary table in the main update clause
|
|
3063
3051
|
def update_table_sql(sql)
|
|
3064
3052
|
sql << ' '
|
|
3065
|
-
|
|
3053
|
+
source_list_append(sql, @opts[:from][0..0])
|
|
3066
3054
|
end
|
|
3067
3055
|
end
|
|
3068
3056
|
end
|
|
@@ -305,38 +305,6 @@ module Sequel
|
|
|
305
305
|
super(sql, :+, args)
|
|
306
306
|
when :<<, :>>
|
|
307
307
|
complex_expression_emulate_append(sql, op, args)
|
|
308
|
-
when :LIKE, :"NOT LIKE"
|
|
309
|
-
sql << '('
|
|
310
|
-
literal_append(sql, args[0])
|
|
311
|
-
sql << (op == :LIKE ? ' REGEXP ' : ' NOT REGEXP ')
|
|
312
|
-
pattern = String.new
|
|
313
|
-
last_c = ''
|
|
314
|
-
args[1].each_char do |c|
|
|
315
|
-
if c == '_' and not pattern.end_with?('\\') and last_c != '\\'
|
|
316
|
-
pattern << '.'
|
|
317
|
-
elsif c == '%' and not pattern.end_with?('\\') and last_c != '\\'
|
|
318
|
-
pattern << '.*'
|
|
319
|
-
elsif c == '[' and not pattern.end_with?('\\') and last_c != '\\'
|
|
320
|
-
pattern << '\['
|
|
321
|
-
elsif c == ']' and not pattern.end_with?('\\') and last_c != '\\'
|
|
322
|
-
pattern << '\]'
|
|
323
|
-
elsif c == '*' and not pattern.end_with?('\\') and last_c != '\\'
|
|
324
|
-
pattern << '\*'
|
|
325
|
-
elsif c == '?' and not pattern.end_with?('\\') and last_c != '\\'
|
|
326
|
-
pattern << '\?'
|
|
327
|
-
else
|
|
328
|
-
pattern << c
|
|
329
|
-
end
|
|
330
|
-
if c == '\\' and last_c == '\\'
|
|
331
|
-
last_c = ''
|
|
332
|
-
else
|
|
333
|
-
last_c = c
|
|
334
|
-
end
|
|
335
|
-
end
|
|
336
|
-
literal_append(sql, pattern)
|
|
337
|
-
sql << " ESCAPE "
|
|
338
|
-
literal_append(sql, "\\")
|
|
339
|
-
sql << ')'
|
|
340
308
|
when :ILIKE, :"NOT ILIKE"
|
|
341
309
|
super(sql, (op == :ILIKE ? :LIKE : :"NOT LIKE"), args)
|
|
342
310
|
when :extract
|
|
@@ -210,7 +210,7 @@ module Sequel
|
|
|
210
210
|
if ops.length > 1 && ops.all?{|op| op[:op] == :add_constraint || op[:op] == :set_column_null}
|
|
211
211
|
null_ops, ops = ops.partition{|op| op[:op] == :set_column_null}
|
|
212
212
|
|
|
213
|
-
# Apply NULL/NOT NULL ops first, since those should be purely
|
|
213
|
+
# Apply NULL/NOT NULL ops first, since those should be purely independent of the constraints.
|
|
214
214
|
null_ops.each{|op| alter_table_sql_list(table, [op]).flatten.each{|sql| execute_ddl(sql)}}
|
|
215
215
|
|
|
216
216
|
# If you are just doing constraints, apply all of them at the same time,
|
|
@@ -677,14 +677,15 @@ module Sequel
|
|
|
677
677
|
super
|
|
678
678
|
end
|
|
679
679
|
|
|
680
|
-
# Return
|
|
681
|
-
# current dataset.
|
|
682
|
-
#
|
|
680
|
+
# Return a string specifying a query explanation for a SELECT of the
|
|
681
|
+
# current dataset. Options:
|
|
682
|
+
# :query_plan :: Use EXPLAIN QUERY PLAN instead of EXPLAIN if true.
|
|
683
683
|
def explain(opts=nil)
|
|
684
684
|
# Load the PrettyTable class, needed for explain output
|
|
685
685
|
Sequel.extension(:_pretty_table) unless defined?(Sequel::PrettyTable)
|
|
686
686
|
|
|
687
|
-
|
|
687
|
+
keyword = (opts && opts[:query_plan]) ? "EXPLAIN QUERY PLAN" : "EXPLAIN"
|
|
688
|
+
ds = db.send(:metadata_dataset).clone(:sql=>"#{keyword} #{select_sql}".freeze)
|
|
688
689
|
rows = ds.all
|
|
689
690
|
Sequel::PrettyTable.string(rows, ds.columns)
|
|
690
691
|
end
|
|
@@ -729,7 +730,7 @@ module Sequel
|
|
|
729
730
|
|
|
730
731
|
# Handle uniqueness violations when inserting, by using a specified
|
|
731
732
|
# resolution algorithm. With no options, uses INSERT OR REPLACE. SQLite
|
|
732
|
-
# supports the following conflict resolution
|
|
733
|
+
# supports the following conflict resolution algorithms: ROLLBACK, ABORT,
|
|
733
734
|
# FAIL, IGNORE and REPLACE.
|
|
734
735
|
#
|
|
735
736
|
# On SQLite 3.24.0+, you can pass a hash to use an ON CONFLICT clause.
|
|
@@ -891,7 +892,7 @@ module Sequel
|
|
|
891
892
|
end
|
|
892
893
|
|
|
893
894
|
# Use from_self for aggregate dataset using VALUES.
|
|
894
|
-
def
|
|
895
|
+
def aggregate_dataset_use_from_self?
|
|
895
896
|
super || @opts[:values]
|
|
896
897
|
end
|
|
897
898
|
|
|
@@ -336,16 +336,20 @@ module Sequel
|
|
|
336
336
|
log_sql << sql
|
|
337
337
|
log_sql << ")"
|
|
338
338
|
end
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
339
|
+
begin
|
|
340
|
+
if block
|
|
341
|
+
log_connection_yield(log_sql, conn, args){cps.execute(ps_args, &block)}
|
|
342
|
+
else
|
|
343
|
+
log_connection_yield(log_sql, conn, args){cps.execute!(ps_args){|r|}}
|
|
344
|
+
case type
|
|
345
|
+
when :insert
|
|
346
|
+
conn.last_insert_row_id
|
|
347
|
+
when :update
|
|
348
|
+
conn.changes
|
|
349
|
+
end
|
|
348
350
|
end
|
|
351
|
+
ensure
|
|
352
|
+
cps.clear_bindings!
|
|
349
353
|
end
|
|
350
354
|
end
|
|
351
355
|
|
|
@@ -49,7 +49,7 @@ module Sequel
|
|
|
49
49
|
else
|
|
50
50
|
# Sequel doesn't allow a nonpositive limit. If the offset
|
|
51
51
|
# is greater than the number of rows, the empty result set
|
|
52
|
-
#
|
|
52
|
+
# should be returned, so use a condition that is always false.
|
|
53
53
|
ds.where(1=>0)
|
|
54
54
|
end
|
|
55
55
|
sql = @opts[:append_sql] || String.new
|
|
@@ -22,7 +22,17 @@ module Sequel
|
|
|
22
22
|
END
|
|
23
23
|
# Error messages for mysql and mysql2 that indicate the current connection should be disconnected
|
|
24
24
|
MYSQL_DATABASE_DISCONNECT_ERRORS = /\A#{Regexp.union(disconnect_errors)}/
|
|
25
|
-
|
|
25
|
+
|
|
26
|
+
# 2027 (CR_MALFORMED_PACKET) deliberately not included (protocol error, not connection error)
|
|
27
|
+
MYSQL_DISCONNECT_ERROR_CODES = [
|
|
28
|
+
2002, # CR_CONNECTION_ERROR
|
|
29
|
+
2006, # CR_SERVER_GONE_ERROR
|
|
30
|
+
2013, # CR_SERVER_LOST
|
|
31
|
+
2014, # CR_COMMANDS_OUT_OF_SYNC
|
|
32
|
+
2055, # CR_SERVER_LOST_EXTENDED
|
|
33
|
+
].freeze
|
|
34
|
+
private_constant :MYSQL_DISCONNECT_ERROR_CODES
|
|
35
|
+
|
|
26
36
|
# Support stored procedures on MySQL
|
|
27
37
|
def call_sproc(name, opts=OPTS, &block)
|
|
28
38
|
args = opts[:args] || []
|
|
@@ -38,7 +38,7 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
|
|
|
38
38
|
|
|
39
39
|
# Disconnects from the database. Once a connection is requested using
|
|
40
40
|
# #hold, the connection is reestablished. Options:
|
|
41
|
-
# :server :: Should be a symbol
|
|
41
|
+
# :server :: Should be a symbol specifying the server to disconnect from,
|
|
42
42
|
# or an array of symbols to specify multiple servers.
|
|
43
43
|
def disconnect(opts=OPTS)
|
|
44
44
|
(opts[:server] ? Array(opts[:server]) : servers).each do |s|
|