sequel 5.93.0 → 5.94.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/lib/sequel/adapters/ado/access.rb +2 -2
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/ibmdb.rb +1 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +2 -2
- data/lib/sequel/adapters/jdbc/oracle.rb +1 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
- data/lib/sequel/adapters/jdbc/sqlserver.rb +1 -1
- data/lib/sequel/adapters/jdbc.rb +21 -7
- data/lib/sequel/adapters/mysql.rb +1 -1
- data/lib/sequel/adapters/mysql2.rb +2 -2
- data/lib/sequel/adapters/odbc.rb +1 -1
- data/lib/sequel/adapters/shared/db2.rb +8 -3
- data/lib/sequel/adapters/shared/mssql.rb +1 -1
- data/lib/sequel/adapters/shared/mysql.rb +2 -2
- data/lib/sequel/adapters/shared/postgres.rb +106 -13
- data/lib/sequel/adapters/shared/sqlite.rb +3 -3
- data/lib/sequel/adapters/tinytds.rb +1 -1
- data/lib/sequel/adapters/trilogy.rb +1 -1
- data/lib/sequel/connection_pool/timed_queue.rb +1 -1
- data/lib/sequel/core.rb +1 -1
- data/lib/sequel/database/misc.rb +3 -3
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +24 -10
- data/lib/sequel/database/schema_methods.rb +60 -26
- data/lib/sequel/dataset/query.rb +10 -2
- data/lib/sequel/dataset/sql.rb +1 -1
- data/lib/sequel/extensions/async_thread_pool.rb +1 -1
- data/lib/sequel/extensions/caller_logging.rb +1 -3
- data/lib/sequel/extensions/eval_inspect.rb +1 -1
- data/lib/sequel/extensions/inflector.rb +2 -2
- data/lib/sequel/extensions/migration.rb +1 -1
- data/lib/sequel/extensions/pg_hstore.rb +1 -1
- data/lib/sequel/extensions/provenance.rb +1 -3
- data/lib/sequel/extensions/schema_dumper.rb +1 -1
- data/lib/sequel/plugins/constraint_validations.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +3 -3
- data/lib/sequel/plugins/unused_associations.rb +4 -2
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05c58f7009f56c4891e863d95ccd90eeb7acdc03f192979ff0d4a203fa1924d4
|
4
|
+
data.tar.gz: 957d465eebddd41b7de48475af26b04f4ae6fb387662257b97b9bdbc682eb197
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb72cd090c58b8246b4a679082f9426f9aecf2d4815dffa2d96fe3be5a15b3e41b9ae7dd17effee49bfab82ac54c11d5d7d6aa67ff2a8aa54040145f5c72a3b0
|
7
|
+
data.tar.gz: 031fcb089d79550e485be488ec6d4b0d84024e4f686ebe953a08189c5b9d6e490c2351246b4258d8b78e9efafd013db61738f19e40a04afbb9fb1ec1796e5e6a
|
@@ -281,7 +281,7 @@ module Sequel
|
|
281
281
|
fetch_ado_schema(:columns, [nil,nil,table_name.to_s,nil]) do |row|
|
282
282
|
rows << AdoSchema::Column.new(row)
|
283
283
|
end
|
284
|
-
rows.
|
284
|
+
rows.sort_by! { |a| a["ORDINAL_POSITION"] }
|
285
285
|
end
|
286
286
|
|
287
287
|
def ado_schema_foreign_keys(table_name)
|
@@ -289,7 +289,7 @@ module Sequel
|
|
289
289
|
fetch_ado_schema(:foreign_keys, [nil,nil,nil,nil,nil,table_name.to_s]) do |row|
|
290
290
|
rows << row
|
291
291
|
end
|
292
|
-
rows.
|
292
|
+
rows.sort_by! { |a| a["ORDINAL"] }
|
293
293
|
end
|
294
294
|
|
295
295
|
def fetch_ado_schema(type, criteria=[])
|
data/lib/sequel/adapters/ado.rb
CHANGED
@@ -234,7 +234,7 @@ module Sequel
|
|
234
234
|
end
|
235
235
|
|
236
236
|
def disconnect_error?(e, opts)
|
237
|
-
super || (e.is_a?(::WIN32OLERuntimeError) && e.message
|
237
|
+
super || (e.is_a?(::WIN32OLERuntimeError) && e.message.include?('Communication link failure'))
|
238
238
|
end
|
239
239
|
|
240
240
|
def rollback_transaction(conn, opts=OPTS)
|
@@ -26,7 +26,7 @@ module Sequel
|
|
26
26
|
|
27
27
|
# Raise a disconnect error if the SQL state of the cause of the exception indicates so.
|
28
28
|
def disconnect_error?(exception, opts)
|
29
|
-
exception.message
|
29
|
+
exception.message.start_with?("Communications link failure") || super
|
30
30
|
end
|
31
31
|
|
32
32
|
# Get the last inserted id using LAST_INSERT_ID().
|
@@ -64,7 +64,7 @@ module Sequel
|
|
64
64
|
|
65
65
|
# Convert tinyint(1) type to boolean
|
66
66
|
def schema_column_type(db_type)
|
67
|
-
db_type
|
67
|
+
db_type.start_with?("tinyint(1)") ? :boolean : super
|
68
68
|
end
|
69
69
|
|
70
70
|
# Run the default connection setting SQL statements.
|
@@ -55,7 +55,7 @@ module Sequel
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def disconnect_error?(exception, opts)
|
58
|
-
super || exception.message
|
58
|
+
super || exception.message.start_with?("Closed Connection")
|
59
59
|
end
|
60
60
|
|
61
61
|
# Default the fetch size for statements to 100, similar to the oci8-based oracle adapter.
|
@@ -98,7 +98,7 @@ module Sequel
|
|
98
98
|
|
99
99
|
# Whether the given exception is due to a foreign key error.
|
100
100
|
def foreign_key_error?(exception)
|
101
|
-
exception.message
|
101
|
+
exception.message.include?('query does not return ResultSet')
|
102
102
|
end
|
103
103
|
|
104
104
|
# Use getLong instead of getInt for converting integers on SQLite, since SQLite does not enforce a limit of 2**32.
|
data/lib/sequel/adapters/jdbc.rb
CHANGED
@@ -305,17 +305,31 @@ module Sequel
|
|
305
305
|
m = output_identifier_meth
|
306
306
|
schema, table = metadata_schema_and_table(table, opts)
|
307
307
|
foreign_keys = {}
|
308
|
+
|
308
309
|
metadata(:getImportedKeys, nil, schema, table) do |r|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
310
|
+
next unless fk_name = r[:fk_name]
|
311
|
+
|
312
|
+
key_seq = r[:key_seq]
|
313
|
+
columns = [key_seq, m.call(r[:fkcolumn_name])]
|
314
|
+
key = [key_seq, m.call(r[:pkcolumn_name])]
|
315
|
+
|
316
|
+
if fk = foreign_keys[fk_name]
|
317
|
+
fk[:columns] << columns
|
318
|
+
fk[:key] << key
|
319
|
+
else
|
320
|
+
foreign_keys[fk_name] = {
|
321
|
+
:name=>m.call(fk_name),
|
322
|
+
:columns=>[columns],
|
323
|
+
:table=>m.call(r[:pktable_name]),
|
324
|
+
:key=>[key]
|
325
|
+
}
|
314
326
|
end
|
315
327
|
end
|
328
|
+
|
329
|
+
fk_keys = [:columns, :key]
|
316
330
|
foreign_keys.values.each do |fk|
|
317
|
-
|
318
|
-
fk[k]
|
331
|
+
fk_keys.each do |k|
|
332
|
+
fk[k].sort!.map!{|_, v| v}
|
319
333
|
end
|
320
334
|
end
|
321
335
|
end
|
@@ -290,7 +290,7 @@ module Sequel
|
|
290
290
|
|
291
291
|
# Convert tinyint(1) type to boolean if convert_tinyint_to_bool is true
|
292
292
|
def schema_column_type(db_type)
|
293
|
-
convert_tinyint_to_bool && db_type
|
293
|
+
convert_tinyint_to_bool && db_type.start_with?("tinyint(1)") ? :boolean : super
|
294
294
|
end
|
295
295
|
end
|
296
296
|
|
@@ -221,13 +221,13 @@ module Sequel
|
|
221
221
|
super ||
|
222
222
|
((conn = opts[:conn]) && !conn.ping) ||
|
223
223
|
(e.is_a?(::Mysql2::Error) &&
|
224
|
-
(e.sql_state
|
224
|
+
((e.sql_state && e.sql_state.start_with?("08")) ||
|
225
225
|
MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message)))
|
226
226
|
end
|
227
227
|
|
228
228
|
# Convert tinyint(1) type to boolean if convert_tinyint_to_bool is true
|
229
229
|
def schema_column_type(db_type)
|
230
|
-
convert_tinyint_to_bool && db_type
|
230
|
+
convert_tinyint_to_bool && db_type.start_with?("tinyint(1)") ? :boolean : super
|
231
231
|
end
|
232
232
|
end
|
233
233
|
|
data/lib/sequel/adapters/odbc.rb
CHANGED
@@ -108,7 +108,7 @@ module Sequel
|
|
108
108
|
from(name).first
|
109
109
|
true
|
110
110
|
rescue DatabaseError => e
|
111
|
-
if e.to_s
|
111
|
+
if e.to_s.include?('Operation not allowed for reason code "7" on table') && v == false
|
112
112
|
# table probably needs reorg
|
113
113
|
reorg(name)
|
114
114
|
v = true
|
@@ -175,8 +175,13 @@ module Sequel
|
|
175
175
|
# Supply columns with NOT NULL if they are part of a composite
|
176
176
|
# primary key or unique constraint
|
177
177
|
def column_list_sql(g)
|
178
|
-
ks =
|
179
|
-
g.constraints.each
|
178
|
+
ks = {}
|
179
|
+
g.constraints.each do |c|
|
180
|
+
case c[:type]
|
181
|
+
when :primary_key, :unique
|
182
|
+
c[:columns].each{|c| ks[c] = true}
|
183
|
+
end
|
184
|
+
end
|
180
185
|
g.columns.each{|c| c[:null] = false if ks.include?(c[:name]) }
|
181
186
|
super
|
182
187
|
end
|
@@ -705,7 +705,7 @@ module Sequel
|
|
705
705
|
|
706
706
|
# Allows you to do a dirty read of uncommitted data using WITH (NOLOCK).
|
707
707
|
def nolock
|
708
|
-
|
708
|
+
cached_lock_style_dataset(:_nolock_ds, :dirty)
|
709
709
|
end
|
710
710
|
|
711
711
|
# Uses OUTER APPLY to join the given table into the current dataset.
|
@@ -456,7 +456,7 @@ module Sequel
|
|
456
456
|
[pk]
|
457
457
|
elsif !(pkc = generator.constraints.select{|con| con[:type] == :primary_key}).empty?
|
458
458
|
pkc.first[:columns]
|
459
|
-
elsif !(pkc = generator.columns.select{|con| con[:primary_key]
|
459
|
+
elsif !(pkc = generator.columns.select{|con| con[:primary_key]}).empty?
|
460
460
|
pkc.map{|c| c[:name]}
|
461
461
|
end
|
462
462
|
else
|
@@ -787,7 +787,7 @@ module Sequel
|
|
787
787
|
|
788
788
|
# Return a cloned dataset which will use LOCK IN SHARE MODE to lock returned rows.
|
789
789
|
def for_share
|
790
|
-
|
790
|
+
cached_lock_style_dataset(:_for_share_ds, :share)
|
791
791
|
end
|
792
792
|
|
793
793
|
# Adds full text filter
|
@@ -48,7 +48,7 @@ module Sequel
|
|
48
48
|
TYPE_TRANSLATOR_DATE = date.freeze
|
49
49
|
bytea = Object.new
|
50
50
|
def bytea.call(str)
|
51
|
-
str = if str
|
51
|
+
str = if str.start_with?('\\x')
|
52
52
|
# PostgreSQL 9.0+ bytea hex format
|
53
53
|
str[2..-1].gsub(/(..)/){|s| s.to_i(16).chr}
|
54
54
|
else
|
@@ -141,6 +141,17 @@ module Sequel
|
|
141
141
|
@operations << {:op => :add_constraint, :type => :exclude, :elements => elements}.merge!(opts)
|
142
142
|
end
|
143
143
|
|
144
|
+
# Alter an existing constraint. Options:
|
145
|
+
# :deferrable :: Modify deferrable setting for constraint (PostgreSQL 9.4+):
|
146
|
+
# true :: DEFERRABLE INITIALLY DEFERRED
|
147
|
+
# false :: NOT DEFERRABLE
|
148
|
+
# :immediate :: DEFERRABLE INITIALLY IMMEDIATE
|
149
|
+
# :enforced :: Set true to use ENFORCED, or false to use NOT ENFORCED (PostgreSQL 18+)
|
150
|
+
# :inherit :: Set true to use INHERIT, or false to use NO INHERIT (PostgreSQL 18+)
|
151
|
+
def alter_constraint(name, opts=OPTS)
|
152
|
+
@operations << {:op => :alter_constraint, :name => name}.merge!(opts)
|
153
|
+
end
|
154
|
+
|
144
155
|
# Validate the constraint with the given name, which should have
|
145
156
|
# been added previously with NOT VALID.
|
146
157
|
def validate_constraint(name)
|
@@ -335,7 +346,7 @@ module Sequel
|
|
335
346
|
hash = {}
|
336
347
|
_check_constraints_ds.where_each(:conrelid=>regclass_oid(table)) do |row|
|
337
348
|
constraint = m.call(row[:constraint])
|
338
|
-
entry = hash[constraint] ||= {:definition=>row[:definition], :columns=>[]}
|
349
|
+
entry = hash[constraint] ||= {:definition=>row[:definition], :columns=>[], :validated=>row[:validated], :enforced=>row[:enforced]}
|
339
350
|
entry[:columns] << m.call(row[:column]) if row[:column]
|
340
351
|
end
|
341
352
|
|
@@ -601,6 +612,8 @@ module Sequel
|
|
601
612
|
:on_update=>fklod_map[row[:on_update]],
|
602
613
|
:on_delete=>fklod_map[row[:on_delete]],
|
603
614
|
:deferrable=>row[:deferrable],
|
615
|
+
:validated=>row[:validated],
|
616
|
+
:enforced=>row[:enforced],
|
604
617
|
:table=>schema ? SQL::QualifiedIdentifier.new(m.call(row[:schema]), m.call(row[:table])) : m.call(row[:table]),
|
605
618
|
}
|
606
619
|
|
@@ -898,11 +911,15 @@ module Sequel
|
|
898
911
|
|
899
912
|
# Dataset used to retrieve CHECK constraint information
|
900
913
|
def _check_constraints_ds
|
901
|
-
@_check_constraints_ds ||=
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
914
|
+
@_check_constraints_ds ||= begin
|
915
|
+
ds = metadata_dataset.
|
916
|
+
from{pg_constraint.as(:co)}.
|
917
|
+
left_join(Sequel[:pg_attribute].as(:att), :attrelid=>:conrelid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:conkey])).
|
918
|
+
where(:contype=>'c').
|
919
|
+
select{[co[:conname].as(:constraint), att[:attname].as(:column), pg_get_constraintdef(co[:oid]).as(:definition)]}
|
920
|
+
|
921
|
+
_add_validated_enforced_constraint_columns(ds)
|
922
|
+
end
|
906
923
|
end
|
907
924
|
|
908
925
|
# Dataset used to retrieve foreign keys referenced by a table
|
@@ -968,6 +985,28 @@ module Sequel
|
|
968
985
|
ds = ds.order_append(Sequel[:nsp][:nspname], Sequel[:cl2][:relname])
|
969
986
|
end
|
970
987
|
|
988
|
+
_add_validated_enforced_constraint_columns(ds)
|
989
|
+
end
|
990
|
+
|
991
|
+
def _add_validated_enforced_constraint_columns(ds)
|
992
|
+
validated_cond = if server_version >= 90100
|
993
|
+
Sequel[:convalidated]
|
994
|
+
# :nocov:
|
995
|
+
else
|
996
|
+
Sequel.cast(true, TrueClass)
|
997
|
+
# :nocov:
|
998
|
+
end
|
999
|
+
ds = ds.select_append(validated_cond.as(:validated))
|
1000
|
+
|
1001
|
+
enforced_cond = if server_version >= 180000
|
1002
|
+
Sequel[:conenforced]
|
1003
|
+
# :nocov:
|
1004
|
+
else
|
1005
|
+
Sequel.cast(true, TrueClass)
|
1006
|
+
# :nocov:
|
1007
|
+
end
|
1008
|
+
ds = ds.select_append(enforced_cond.as(:enforced))
|
1009
|
+
|
971
1010
|
ds
|
972
1011
|
end
|
973
1012
|
|
@@ -1140,6 +1179,31 @@ module Sequel
|
|
1140
1179
|
"ADD COLUMN#{' IF NOT EXISTS' if op[:if_not_exists]} #{column_definition_sql(op)}"
|
1141
1180
|
end
|
1142
1181
|
|
1182
|
+
def alter_table_alter_constraint_sql(table, op)
|
1183
|
+
sql = String.new
|
1184
|
+
sql << "ALTER CONSTRAINT #{quote_identifier(op[:name])}"
|
1185
|
+
|
1186
|
+
constraint_deferrable_sql_append(sql, op[:deferrable])
|
1187
|
+
|
1188
|
+
case op[:enforced]
|
1189
|
+
when nil
|
1190
|
+
when false
|
1191
|
+
sql << " NOT ENFORCED"
|
1192
|
+
else
|
1193
|
+
sql << " ENFORCED"
|
1194
|
+
end
|
1195
|
+
|
1196
|
+
case op[:inherit]
|
1197
|
+
when nil
|
1198
|
+
when false
|
1199
|
+
sql << " NO INHERIT"
|
1200
|
+
else
|
1201
|
+
sql << " INHERIT"
|
1202
|
+
end
|
1203
|
+
|
1204
|
+
sql
|
1205
|
+
end
|
1206
|
+
|
1143
1207
|
def alter_table_generator_class
|
1144
1208
|
Postgres::AlterTableGenerator
|
1145
1209
|
end
|
@@ -1233,9 +1297,9 @@ module Sequel
|
|
1233
1297
|
end
|
1234
1298
|
|
1235
1299
|
# PostgreSQL can't combine rename_column operations, and it can combine
|
1236
|
-
#
|
1300
|
+
# validate_constraint and alter_constraint operations.
|
1237
1301
|
def combinable_alter_table_op?(op)
|
1238
|
-
(super || op[:op] == :validate_constraint) && op[:op] != :rename_column
|
1302
|
+
(super || op[:op] == :validate_constraint || op[:op] == :alter_constraint) && op[:op] != :rename_column
|
1239
1303
|
end
|
1240
1304
|
|
1241
1305
|
VALID_CLIENT_MIN_MESSAGES = %w'DEBUG5 DEBUG4 DEBUG3 DEBUG2 DEBUG1 LOG NOTICE WARNING ERROR FATAL PANIC'.freeze.each(&:freeze)
|
@@ -1269,7 +1333,7 @@ module Sequel
|
|
1269
1333
|
sqls
|
1270
1334
|
end
|
1271
1335
|
|
1272
|
-
# Handle
|
1336
|
+
# Handle PostgreSQL-specific constraint features.
|
1273
1337
|
def constraint_definition_sql(constraint)
|
1274
1338
|
case type = constraint[:type]
|
1275
1339
|
when :exclude
|
@@ -1293,6 +1357,9 @@ module Sequel
|
|
1293
1357
|
end
|
1294
1358
|
else # when :foreign_key, :check
|
1295
1359
|
sql = super
|
1360
|
+
if constraint[:not_enforced]
|
1361
|
+
sql << " NOT ENFORCED"
|
1362
|
+
end
|
1296
1363
|
if constraint[:not_valid]
|
1297
1364
|
sql << " NOT VALID"
|
1298
1365
|
end
|
@@ -1300,6 +1367,13 @@ module Sequel
|
|
1300
1367
|
end
|
1301
1368
|
end
|
1302
1369
|
|
1370
|
+
def column_definition_add_references_sql(sql, column)
|
1371
|
+
super
|
1372
|
+
if column[:not_enforced]
|
1373
|
+
sql << " NOT ENFORCED"
|
1374
|
+
end
|
1375
|
+
end
|
1376
|
+
|
1303
1377
|
def database_specific_error_class_from_sqlstate(sqlstate)
|
1304
1378
|
if sqlstate == '23P01'
|
1305
1379
|
ExclusionConstraintViolation
|
@@ -1369,7 +1443,8 @@ module Sequel
|
|
1369
1443
|
# SQL statement to create database function.
|
1370
1444
|
def create_function_sql(name, definition, opts=OPTS)
|
1371
1445
|
args = opts[:args]
|
1372
|
-
|
1446
|
+
in_out = %w'OUT INOUT'
|
1447
|
+
if (!opts[:args].is_a?(Array) || !opts[:args].any?{|a| Array(a).length == 3 && in_out.include?(a[2].to_s)})
|
1373
1448
|
returns = opts[:returns] || 'void'
|
1374
1449
|
end
|
1375
1450
|
language = opts[:language] || 'SQL'
|
@@ -1932,9 +2007,22 @@ module Sequel
|
|
1932
2007
|
end
|
1933
2008
|
end
|
1934
2009
|
|
2010
|
+
# Return a cloned dataset which will use FOR KEY SHARE to lock returned rows.
|
2011
|
+
# Supported on PostgreSQL 9.3+.
|
2012
|
+
def for_key_share
|
2013
|
+
cached_lock_style_dataset(:_for_key_share_ds, :key_share)
|
2014
|
+
end
|
2015
|
+
|
2016
|
+
# Return a cloned dataset which will use FOR NO KEY UPDATE to lock returned rows.
|
2017
|
+
# This is generally a better choice than using for_update on PostgreSQL, unless
|
2018
|
+
# you will be deleting the row or modifying a key column. Supported on PostgreSQL 9.3+.
|
2019
|
+
def for_no_key_update
|
2020
|
+
cached_lock_style_dataset(:_for_no_key_update_ds, :no_key_update)
|
2021
|
+
end
|
2022
|
+
|
1935
2023
|
# Return a cloned dataset which will use FOR SHARE to lock returned rows.
|
1936
2024
|
def for_share
|
1937
|
-
|
2025
|
+
cached_lock_style_dataset(:_for_share_ds, :share)
|
1938
2026
|
end
|
1939
2027
|
|
1940
2028
|
# Run a full text search on PostgreSQL. By default, searching for the inclusion
|
@@ -2710,8 +2798,13 @@ module Sequel
|
|
2710
2798
|
# Use SKIP LOCKED if skipping locked rows.
|
2711
2799
|
def select_lock_sql(sql)
|
2712
2800
|
lock = @opts[:lock]
|
2713
|
-
|
2801
|
+
case lock
|
2802
|
+
when :share
|
2714
2803
|
sql << ' FOR SHARE'
|
2804
|
+
when :no_key_update
|
2805
|
+
sql << ' FOR NO KEY UPDATE'
|
2806
|
+
when :key_share
|
2807
|
+
sql << ' FOR KEY SHARE'
|
2715
2808
|
else
|
2716
2809
|
super
|
2717
2810
|
end
|
@@ -95,14 +95,14 @@ module Sequel
|
|
95
95
|
metadata_dataset.with_sql("PRAGMA index_list(?)", im.call(table)).each do |r|
|
96
96
|
if opts[:only_autocreated]
|
97
97
|
# If specifically asked for only autocreated indexes, then return those an only those
|
98
|
-
next unless r[:name]
|
98
|
+
next unless r[:name].start_with?('sqlite_autoindex_')
|
99
99
|
elsif r.has_key?(:origin)
|
100
100
|
# If origin is set, then only exclude primary key indexes and partial indexes
|
101
101
|
next if r[:origin] == 'pk'
|
102
102
|
next if r[:partial].to_i == 1
|
103
103
|
else
|
104
104
|
# When :origin key not present, assume any autoindex could be a primary key one and exclude it
|
105
|
-
next if r[:name]
|
105
|
+
next if r[:name].start_with?('sqlite_autoindex_')
|
106
106
|
end
|
107
107
|
|
108
108
|
indexes[m.call(r[:name])] = {:unique=>r[:unique].to_i==1}
|
@@ -302,7 +302,7 @@ module Sequel
|
|
302
302
|
|
303
303
|
# A name to use for the backup table
|
304
304
|
def backup_table_name(table, opts=OPTS)
|
305
|
-
table = table.
|
305
|
+
table = table.delete('`')
|
306
306
|
(opts[:times]||1000).times do |i|
|
307
307
|
table_name = "#{table}_backup#{i}"
|
308
308
|
return table_name unless table_exists?(table_name)
|
@@ -236,7 +236,7 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
|
|
236
236
|
def preconnect(concurrent = false)
|
237
237
|
if concurrent
|
238
238
|
if times = sync{@max_size > (size = @size[0]) ? @max_size - size : false}
|
239
|
-
|
239
|
+
Array.new(times){Thread.new{if conn = try_make_new; @queue.push(conn) end}}.map(&:value)
|
240
240
|
end
|
241
241
|
else
|
242
242
|
while conn = try_make_new
|
data/lib/sequel/core.rb
CHANGED
data/lib/sequel/database/misc.rb
CHANGED
@@ -36,13 +36,13 @@ module Sequel
|
|
36
36
|
|
37
37
|
# Register a hook that will be run when a new Database is instantiated. It is
|
38
38
|
# called with the new database handle.
|
39
|
-
def self.after_initialize
|
40
|
-
raise Error, "must provide block to after_initialize" unless
|
39
|
+
def self.after_initialize
|
40
|
+
raise Error, "must provide block to after_initialize" unless defined?(yield)
|
41
41
|
Sequel.synchronize do
|
42
42
|
previous = @initialize_hook
|
43
43
|
@initialize_hook = proc do |db|
|
44
44
|
previous.call(db)
|
45
|
-
|
45
|
+
yield(db)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -269,7 +269,7 @@ module Sequel
|
|
269
269
|
def column_schema_to_ruby_default(default, type)
|
270
270
|
return default unless default.is_a?(String)
|
271
271
|
if COLUMN_SCHEMA_DATETIME_TYPES.include?(type)
|
272
|
-
if /now|today|CURRENT|getdate|\ADate\(\)\z/i
|
272
|
+
if /now|today|CURRENT|getdate|\ADate\(\)\z/i =~ default
|
273
273
|
if type == :date
|
274
274
|
return Sequel::CURRENT_DATE
|
275
275
|
else
|
@@ -126,17 +126,21 @@ module Sequel
|
|
126
126
|
# (:restrict, :cascade, :set_null, :set_default, :no_action).
|
127
127
|
# :primary_key :: Make the column as a single primary key column. This should not
|
128
128
|
# be used if you want a single autoincrementing primary key column
|
129
|
-
# (use the primary_key method in that case).
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
129
|
+
# (use the primary_key method in that case). Can be a hash to provide
|
130
|
+
# options for the constraint:
|
131
|
+
# :name :: The name to give the primary key constraint.
|
132
|
+
# :deferrable :: Sets whether the primary key constraint is deferrable.
|
133
|
+
# :primary_key_constraint_name :: Older option to name primary key constraint.
|
134
|
+
# :primary_key_deferrable :: Older option to set primary key constraint as deferrable.
|
133
135
|
# :type :: Overrides the type given as the argument. Generally not used by column
|
134
136
|
# itself, but can be passed as an option to other methods that call column.
|
135
137
|
# :unique :: Mark the column as unique, generally has the same effect as
|
136
|
-
# creating a unique index on the column.
|
137
|
-
#
|
138
|
-
#
|
139
|
-
#
|
138
|
+
# creating a unique index on the column. Can be a hash to provide options for
|
139
|
+
# the constraint:
|
140
|
+
# :name :: The name to give the unique constraint.
|
141
|
+
# :deferrable :: Sets whether the unique constraint is deferrable.
|
142
|
+
# :unique_constraint_name :: Older option to name unique constraint.
|
143
|
+
# :unique_deferrable :: Older option to set unique constraint as deferrable.
|
140
144
|
#
|
141
145
|
# PostgreSQL specific options:
|
142
146
|
#
|
@@ -178,6 +182,7 @@ module Sequel
|
|
178
182
|
# :deferrable :: Whether the CHECK constraint should be marked DEFERRABLE.
|
179
183
|
#
|
180
184
|
# PostgreSQL specific options:
|
185
|
+
# :not_enforced :: Whether the CHECK constraint should be marked NOT ENFORCED.
|
181
186
|
# :not_valid :: Whether the CHECK constraint should be marked NOT VALID.
|
182
187
|
def constraint(name, *args, &block)
|
183
188
|
opts = name.is_a?(Hash) ? name : {:name=>name}
|
@@ -197,9 +202,18 @@ module Sequel
|
|
197
202
|
#
|
198
203
|
# :foreign_key_constraint_name :: The name to give the foreign key constraint
|
199
204
|
#
|
205
|
+
# PostgreSQL specific options:
|
206
|
+
#
|
207
|
+
# :not_enforced :: Whether the foreign key constraint should be marked NOT ENFORCED.
|
208
|
+
#
|
200
209
|
# If you want a foreign key constraint without adding a column (usually because it is a
|
201
|
-
# composite foreign key), you can provide an array of columns as the first argument
|
202
|
-
#
|
210
|
+
# composite foreign key), you can provide an array of columns as the first argument.
|
211
|
+
# This changes the method to accept constraint options instead of column options.
|
212
|
+
# You can provide the :name option to name the constraint.
|
213
|
+
#
|
214
|
+
# PostgreSQL specific options:
|
215
|
+
#
|
216
|
+
# :not_enforced :: Whether the foreign key constraint should be marked NOT ENFORCED.
|
203
217
|
#
|
204
218
|
# foreign_key([:artist_name, :artist_location], :artists, name: :artist_fk)
|
205
219
|
# # ADD CONSTRAINT artist_fk FOREIGN KEY (artist_name, artist_location) REFERENCES artists
|
@@ -605,36 +605,63 @@ module Sequel
|
|
605
605
|
end
|
606
606
|
end
|
607
607
|
|
608
|
-
# Add primary key SQL fragment to column creation SQL.
|
608
|
+
# Add primary key SQL fragment to column creation SQL if column is a primary key.
|
609
609
|
def column_definition_primary_key_sql(sql, column)
|
610
|
-
if column[:primary_key]
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
610
|
+
column_definition_add_primary_key_sql(sql, column) if column[:primary_key]
|
611
|
+
end
|
612
|
+
|
613
|
+
# Add primary key SQL fragment to column creation SQL (column should be a primary key).
|
614
|
+
def column_definition_add_primary_key_sql(sql, column)
|
615
|
+
constraint = column_definition_constraint_hash(column, :primary_key)
|
616
|
+
append_named_constraint_prefix_sql(sql, constraint[:name])
|
617
|
+
sql << " " << primary_key_constraint_sql_fragment(constraint)
|
618
|
+
constraint_deferrable_sql_append(sql, constraint[:deferrable])
|
617
619
|
end
|
618
620
|
|
619
|
-
# Add foreign key reference SQL fragment to column creation SQL.
|
621
|
+
# Add foreign key reference SQL fragment to column creation SQL if column is a foreign key.
|
620
622
|
def column_definition_references_sql(sql, column)
|
621
|
-
if column[:table]
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
623
|
+
column_definition_add_references_sql(sql, column) if column[:table]
|
624
|
+
end
|
625
|
+
|
626
|
+
# Add foreign key reference SQL fragment to column creation SQL (column should be a foreign key).
|
627
|
+
def column_definition_add_references_sql(sql, column)
|
628
|
+
append_named_constraint_prefix_sql(sql, column[:foreign_key_constraint_name])
|
629
|
+
sql << column_references_column_constraint_sql(column)
|
627
630
|
end
|
628
631
|
|
629
|
-
# Add unique constraint SQL fragment to column creation SQL.
|
632
|
+
# Add unique constraint SQL fragment to column creation SQL if column has a unique constraint.
|
630
633
|
def column_definition_unique_sql(sql, column)
|
631
|
-
if column[:unique]
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
634
|
+
column_definition_add_unique_sql(sql, column) if column[:unique]
|
635
|
+
end
|
636
|
+
|
637
|
+
# Add unique constraint SQL fragment to column creation SQL (column should have unique constraint).
|
638
|
+
def column_definition_add_unique_sql(sql, column)
|
639
|
+
constraint = column_definition_constraint_hash(column, :unique)
|
640
|
+
append_named_constraint_prefix_sql(sql, constraint[:name])
|
641
|
+
sql << ' ' << unique_constraint_sql_fragment(constraint)
|
642
|
+
constraint_deferrable_sql_append(sql, constraint[:deferrable])
|
643
|
+
end
|
644
|
+
|
645
|
+
# Add the name of the constraint to the column creation SQL.
|
646
|
+
def append_named_constraint_prefix_sql(sql, name)
|
647
|
+
sql << " CONSTRAINT #{quote_identifier(name)}" if name
|
648
|
+
end
|
649
|
+
|
650
|
+
# Return a hash of constraint options for the primary key or column
|
651
|
+
# unique constraint.
|
652
|
+
def column_definition_constraint_hash(column, prefix)
|
653
|
+
constraint = column[prefix]
|
654
|
+
constraint = constraint.is_a?(Hash) ? constraint.dup : {}
|
655
|
+
|
656
|
+
if name = column[:"#{prefix}_constraint_name"]
|
657
|
+
constraint[:name] = name
|
637
658
|
end
|
659
|
+
|
660
|
+
if column.has_key?(:"#{prefix}_deferrable")
|
661
|
+
constraint[:deferrable] = column[:"#{prefix}_deferrable"]
|
662
|
+
end
|
663
|
+
|
664
|
+
constraint
|
638
665
|
end
|
639
666
|
|
640
667
|
# SQL for all given columns, used inside a CREATE TABLE block.
|
@@ -677,7 +704,7 @@ module Sequel
|
|
677
704
|
check = constraint[:check]
|
678
705
|
check = check.first if check.is_a?(Array) && check.length == 1
|
679
706
|
check = filter_expr(check)
|
680
|
-
check = "(#{check})" unless check
|
707
|
+
check = "(#{check})" unless check.start_with?('(') && check.end_with?(')')
|
681
708
|
sql << "CHECK #{check}"
|
682
709
|
when :primary_key
|
683
710
|
sql << "#{primary_key_constraint_sql_fragment(constraint)} #{literal(constraint[:columns])}"
|
@@ -733,17 +760,24 @@ module Sequel
|
|
733
760
|
def create_table_sql(name, generator, options)
|
734
761
|
unless supports_named_column_constraints?
|
735
762
|
# Split column constraints into table constraints if they have a name
|
763
|
+
fk_opt_keys = [:key, :on_delete, :on_update, :deferrable]
|
736
764
|
generator.columns.each do |c|
|
737
765
|
if (constraint_name = c.delete(:foreign_key_constraint_name)) && (table = c.delete(:table))
|
738
766
|
opts = {}
|
739
767
|
opts[:name] = constraint_name
|
740
|
-
|
768
|
+
fk_opt_keys.each{|k| opts[k] = c[k]}
|
741
769
|
generator.foreign_key([c[:name]], table, opts)
|
742
770
|
end
|
743
|
-
|
771
|
+
|
772
|
+
if c[:unique].is_a?(Hash) && c[:unique][:name]
|
773
|
+
generator.unique(c[:name], c.delete(:unique))
|
774
|
+
elsif (constraint_name = c.delete(:unique_constraint_name)) && c.delete(:unique)
|
744
775
|
generator.unique(c[:name], :name=>constraint_name)
|
745
776
|
end
|
746
|
-
|
777
|
+
|
778
|
+
if c[:primary_key].is_a?(Hash) && c[:primary_key][:name]
|
779
|
+
generator.primary_key([c[:name]], c.delete(:primary_key))
|
780
|
+
elsif (constraint_name = c.delete(:primary_key_constraint_name)) && c.delete(:primary_key)
|
747
781
|
generator.primary_key([c[:name]], :name=>constraint_name)
|
748
782
|
end
|
749
783
|
end
|
data/lib/sequel/dataset/query.rb
CHANGED
@@ -231,8 +231,7 @@ module Sequel
|
|
231
231
|
#
|
232
232
|
# DB[:table].for_update # SELECT * FROM table FOR UPDATE
|
233
233
|
def for_update
|
234
|
-
|
235
|
-
cached_dataset(:_for_update_ds){lock_style(:update)}
|
234
|
+
cached_lock_style_dataset(:_for_update_ds, :update)
|
236
235
|
end
|
237
236
|
|
238
237
|
# Returns a copy of the dataset with the source changed. If no
|
@@ -1462,6 +1461,15 @@ module Sequel
|
|
1462
1461
|
end
|
1463
1462
|
end
|
1464
1463
|
|
1464
|
+
# Internals of for_update and adapter-specific lock methods.
|
1465
|
+
# Returns receiver if it already uses this lock style, and a cached
|
1466
|
+
# dataset using the given key otherwise. The key could be derived from
|
1467
|
+
# the style, but doing so would require allocation, so pass it in as
|
1468
|
+
# an argument.
|
1469
|
+
def cached_lock_style_dataset(key, style)
|
1470
|
+
opts[:lock] == style ? self : cached_dataset(key){lock_style(style)}
|
1471
|
+
end
|
1472
|
+
|
1465
1473
|
# The default :qualify option to use for join tables if one is not specified.
|
1466
1474
|
def default_join_table_qualification
|
1467
1475
|
:symbol
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -1339,7 +1339,7 @@ module Sequel
|
|
1339
1339
|
# SQL fragment specifying a JOIN type, converts underscores to
|
1340
1340
|
# spaces and upcases.
|
1341
1341
|
def join_type_sql(join_type)
|
1342
|
-
"#{join_type.to_s.
|
1342
|
+
"#{join_type.to_s.tr('_', ' ').upcase} JOIN"
|
1343
1343
|
end
|
1344
1344
|
|
1345
1345
|
# Append USING clause for JOIN USING
|
@@ -357,7 +357,7 @@ module Sequel
|
|
357
357
|
define_singleton_method(:async_job_class){proxy_klass}
|
358
358
|
|
359
359
|
queue = @async_thread_queue = Queue.new
|
360
|
-
pool = @async_thread_pool = num_async_threads
|
360
|
+
pool = @async_thread_pool = Array.new(num_async_threads){JobProcessor.new(queue)}
|
361
361
|
ObjectSpace.define_finalizer(db, JobProcessor.create_finalizer(queue, pool))
|
362
362
|
|
363
363
|
extend_datasets(DatasetMethods)
|
@@ -60,9 +60,7 @@ module Sequel
|
|
60
60
|
def external_caller_for_log
|
61
61
|
ignore = caller_logging_ignore
|
62
62
|
c = caller.find do |line|
|
63
|
-
!(line.start_with?(SEQUEL_LIB_PATH) ||
|
64
|
-
line.start_with?(RUBY_STDLIB) ||
|
65
|
-
line.start_with?(INTERNAL) ||
|
63
|
+
!(line.start_with?(SEQUEL_LIB_PATH, RUBY_STDLIB, INTERNAL) ||
|
66
64
|
(ignore && line =~ ignore))
|
67
65
|
end
|
68
66
|
|
@@ -66,7 +66,7 @@ module Sequel
|
|
66
66
|
# in the order they were defined.
|
67
67
|
klass = self.class
|
68
68
|
args = inspect_args.map do |arg|
|
69
|
-
if arg.is_a?(String) && arg
|
69
|
+
if arg.is_a?(String) && arg.start_with?('*')
|
70
70
|
# Special case string arguments starting with *, indicating that
|
71
71
|
# they should return an array to be splatted as the remaining arguments.
|
72
72
|
# Allow calling private methods to get inspect output.
|
@@ -159,7 +159,7 @@ class String
|
|
159
159
|
# Example
|
160
160
|
# "puni_puni".dasherize #=> "puni-puni"
|
161
161
|
def dasherize
|
162
|
-
|
162
|
+
tr('_', '-')
|
163
163
|
end
|
164
164
|
|
165
165
|
# Removes the module part from the expression in the string
|
@@ -189,7 +189,7 @@ class String
|
|
189
189
|
# "employee_salary" #=> "Employee salary"
|
190
190
|
# "author_id" #=> "Author"
|
191
191
|
def humanize
|
192
|
-
gsub(/_id$/, "").
|
192
|
+
gsub(/_id$/, "").tr('_', " ").capitalize
|
193
193
|
end
|
194
194
|
|
195
195
|
# Returns the plural form of the word in the string.
|
@@ -845,7 +845,7 @@ module Sequel
|
|
845
845
|
begin
|
846
846
|
db.create_table(table){String c, :primary_key=>true}
|
847
847
|
rescue Sequel::DatabaseError => e
|
848
|
-
if db.database_type == :mysql && e.message
|
848
|
+
if db.database_type == :mysql && e.message.include?('max key length')
|
849
849
|
# Handle case where MySQL is used with utf8mb4 charset default, which
|
850
850
|
# only allows a maximum length of about 190 characters for string
|
851
851
|
# primary keys due to InnoDB limitations.
|
@@ -136,7 +136,7 @@ module Sequel
|
|
136
136
|
module DatabaseMethods
|
137
137
|
def self.extended(db)
|
138
138
|
db.instance_exec do
|
139
|
-
add_named_conversion_proc(:hstore
|
139
|
+
add_named_conversion_proc(:hstore){|v| HStore.parse(v)}
|
140
140
|
@schema_type_classes[:hstore] = HStore
|
141
141
|
end
|
142
142
|
end
|
@@ -97,9 +97,7 @@ module Sequel
|
|
97
97
|
def provenance_source
|
98
98
|
ignore = db.opts[:provenance_caller_ignore]
|
99
99
|
caller.find do |line|
|
100
|
-
!(line.start_with?(SEQUEL_LIB_PATH) ||
|
101
|
-
line.start_with?(RUBY_STDLIB) ||
|
102
|
-
line.start_with?(INTERNAL) ||
|
100
|
+
!(line.start_with?(SEQUEL_LIB_PATH, RUBY_STDLIB, INTERNAL) ||
|
103
101
|
(ignore && line =~ ignore))
|
104
102
|
end
|
105
103
|
end
|
@@ -221,7 +221,7 @@ END_MIG
|
|
221
221
|
else
|
222
222
|
col_opts = if options[:same_db]
|
223
223
|
h = {:type=>schema[:db_type]}
|
224
|
-
if database_type == :mysql && h[:type]
|
224
|
+
if database_type == :mysql && h[:type].start_with?("timestamp")
|
225
225
|
h[:null] = true
|
226
226
|
end
|
227
227
|
if database_type == :mssql && schema[:max_length]
|
@@ -164,7 +164,7 @@ module Sequel
|
|
164
164
|
arg = constraint_validation_int_range(arg)
|
165
165
|
type = :includes
|
166
166
|
when *OPERATOR_MAP.keys
|
167
|
-
arg = arg.to_i if type.to_s
|
167
|
+
arg = arg.to_i if type.to_s.start_with?('int_')
|
168
168
|
operator = OPERATOR_MAP[type]
|
169
169
|
type = :operator
|
170
170
|
end
|
@@ -370,9 +370,9 @@ module Sequel
|
|
370
370
|
end
|
371
371
|
|
372
372
|
# Convert the receiver to a JSON data structure using the given arguments.
|
373
|
-
def to_json_data(*args
|
374
|
-
if
|
375
|
-
to_json(*args){|x| return
|
373
|
+
def to_json_data(*args)
|
374
|
+
if defined?(yield)
|
375
|
+
to_json(*args){|x| return yield(x)}
|
376
376
|
else
|
377
377
|
to_json(*args){|x| return x}
|
378
378
|
end
|
@@ -347,6 +347,8 @@ module Sequel
|
|
347
347
|
coverage_data = options[:coverage_data] || Sequel.parse_json(File.binread(@unused_associations_coverage_file))
|
348
348
|
|
349
349
|
unused_associations_data = {}
|
350
|
+
to_many_modification_methods = [:adder, :remover, :clearer]
|
351
|
+
modification_methods = [:setter, :adder, :remover, :clearer]
|
350
352
|
|
351
353
|
([self] + descendants).each do |sc|
|
352
354
|
next unless cov_data = coverage_data[sc.name]
|
@@ -383,8 +385,8 @@ module Sequel
|
|
383
385
|
if !info[:used]
|
384
386
|
(unused_associations_data[sc.name] ||= {})[assoc.to_s] = 'unused'
|
385
387
|
elsif unused = info[:unused]
|
386
|
-
if unused.include?(:setter) ||
|
387
|
-
|
388
|
+
if unused.include?(:setter) || to_many_modification_methods.all?{|k| unused.include?(k)}
|
389
|
+
modification_methods.each do |k|
|
388
390
|
unused.delete(k)
|
389
391
|
end
|
390
392
|
unused << :read_only
|
data/lib/sequel/version.rb
CHANGED
@@ -6,7 +6,7 @@ module Sequel
|
|
6
6
|
|
7
7
|
# The minor version of Sequel. Bumped for every non-patch level
|
8
8
|
# release, generally around once a month.
|
9
|
-
MINOR =
|
9
|
+
MINOR = 94
|
10
10
|
|
11
11
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
12
12
|
# releases that fix regressions from previous versions.
|