sequel 5.102.0 → 5.103.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/MIT-LICENSE +1 -1
- data/lib/sequel/adapters/jdbc/derby.rb +2 -0
- data/lib/sequel/adapters/jdbc/h2.rb +2 -2
- data/lib/sequel/adapters/postgres.rb +1 -1
- data/lib/sequel/adapters/shared/mssql.rb +3 -3
- data/lib/sequel/adapters/shared/mysql.rb +5 -4
- data/lib/sequel/adapters/shared/postgres.rb +16 -16
- data/lib/sequel/adapters/shared/sqlite.rb +3 -3
- data/lib/sequel/adapters/sqlite.rb +1 -1
- data/lib/sequel/adapters/tinytds.rb +1 -1
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +13 -7
- data/lib/sequel/connection_pool/timed_queue.rb +11 -6
- data/lib/sequel/database/schema_generator.rb +36 -5
- data/lib/sequel/database/schema_methods.rb +1 -1
- data/lib/sequel/dataset/placeholder_literalizer.rb +3 -0
- data/lib/sequel/dataset/prepared_statements.rb +7 -4
- data/lib/sequel/dataset/query.rb +6 -3
- data/lib/sequel/dataset/sql.rb +6 -1
- data/lib/sequel/extensions/dataset_run.rb +2 -2
- data/lib/sequel/extensions/date_arithmetic.rb +6 -6
- data/lib/sequel/extensions/lit_require_frozen.rb +131 -0
- data/lib/sequel/extensions/migration.rb +14 -17
- data/lib/sequel/extensions/pg_enum.rb +1 -1
- data/lib/sequel/model/associations.rb +1 -1
- data/lib/sequel/plugins/dirty.rb +5 -2
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/serialization.rb +10 -1
- data/lib/sequel/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 955bca9c729dcd1f54079d4d48d7ac162b6d7e2b234857cfd80d228117541e5a
|
|
4
|
+
data.tar.gz: fe96ad60b73bd55cbaec0f62ba0b977cb79a7ba23fa33a392116b54ca5e7ef34
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 783fa47d72067acb98193be788f133891839984441d0ca763c6be92421b99d294c1710b52e7538a1725fe476bd17b16a1796f68d96017f3e07ef12cc34a2181e
|
|
7
|
+
data.tar.gz: 38f08e76546e3cfee1fa4c520b9d524b1558608572532a940ab06c57ddb50b2ec7766978ab020d9754af415fbd679383d44a506018cca141c0c46ba9f62271cc
|
data/MIT-LICENSE
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Copyright (c) 2007-2008 Sharon Rosner
|
|
2
|
-
Copyright (c) 2008-
|
|
2
|
+
Copyright (c) 2008-2026 Jeremy Evans and contributors
|
|
3
3
|
|
|
4
4
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
5
|
of this software and associated documentation files (the "Software"), to
|
|
@@ -18,7 +18,7 @@ module Sequel
|
|
|
18
18
|
include AutoCastDateAndTime
|
|
19
19
|
|
|
20
20
|
def commit_prepared_transaction(transaction_id, opts=OPTS)
|
|
21
|
-
run("COMMIT TRANSACTION #{transaction_id}", opts)
|
|
21
|
+
run("COMMIT TRANSACTION #{transaction_id}".freeze, opts)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def database_type
|
|
@@ -36,7 +36,7 @@ module Sequel
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def rollback_prepared_transaction(transaction_id, opts=OPTS)
|
|
39
|
-
run("ROLLBACK TRANSACTION #{transaction_id}", opts)
|
|
39
|
+
run("ROLLBACK TRANSACTION #{transaction_id}".freeze, opts)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
# H2 uses an IDENTITY type for primary keys
|
|
@@ -106,7 +106,7 @@ module Sequel
|
|
|
106
106
|
values << value
|
|
107
107
|
end
|
|
108
108
|
|
|
109
|
-
sql = "DECLARE #{declarations.join(', ')}; EXECUTE @RC = #{name} #{values.join(', ')}; SELECT #{names.join(', ')}"
|
|
109
|
+
sql = "DECLARE #{declarations.join(', ')}; EXECUTE @RC = #{name} #{values.join(', ')}; SELECT #{names.join(', ')}".freeze
|
|
110
110
|
|
|
111
111
|
ds = dataset.with_sql(sql)
|
|
112
112
|
ds = ds.server(opts[:server]) if opts[:server]
|
|
@@ -400,7 +400,7 @@ 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
|
-
run(ds.into(name).sql)
|
|
403
|
+
run(ds.into(name).sql.freeze)
|
|
404
404
|
end
|
|
405
405
|
|
|
406
406
|
DATABASE_ERROR_REGEXPS = {
|
|
@@ -878,7 +878,7 @@ module Sequel
|
|
|
878
878
|
elsif @opts[:output]
|
|
879
879
|
# no transaction: our multi_insert_sql_strategy should guarantee
|
|
880
880
|
# that there's only ever a single statement.
|
|
881
|
-
sql = multi_insert_sql(columns, values)[0]
|
|
881
|
+
sql = multi_insert_sql(columns, values)[0].freeze
|
|
882
882
|
naked.with_sql(sql).map{|v| v.length == 1 ? v.values.first : v}
|
|
883
883
|
else
|
|
884
884
|
super
|
|
@@ -40,7 +40,7 @@ module Sequel
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def commit_prepared_transaction(transaction_id, opts=OPTS)
|
|
43
|
-
run("XA COMMIT #{literal(transaction_id)}", opts)
|
|
43
|
+
run("XA COMMIT #{literal(transaction_id)}".freeze, opts)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
def database_type
|
|
@@ -103,7 +103,7 @@ module Sequel
|
|
|
103
103
|
sql += " FROM #{literal(schema)}"
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
metadata_dataset.with_sql(sql).each do |r|
|
|
106
|
+
metadata_dataset.with_sql(sql.freeze).each do |r|
|
|
107
107
|
name = r[:Key_name]
|
|
108
108
|
next if name == 'PRIMARY'
|
|
109
109
|
name = m.call(name)
|
|
@@ -115,7 +115,7 @@ module Sequel
|
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
def rollback_prepared_transaction(transaction_id, opts=OPTS)
|
|
118
|
-
run("XA ROLLBACK #{literal(transaction_id)}", opts)
|
|
118
|
+
run("XA ROLLBACK #{literal(transaction_id)}".freeze, opts)
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
# Whether the database is MariaDB and not MySQL
|
|
@@ -780,7 +780,8 @@ module Sequel
|
|
|
780
780
|
# Load the PrettyTable class, needed for explain output
|
|
781
781
|
Sequel.extension(:_pretty_table) unless defined?(Sequel::PrettyTable)
|
|
782
782
|
|
|
783
|
-
|
|
783
|
+
sql = ((opts[:extended] && (db.mariadb? || db.server_version < 50700)) ? 'EXPLAIN EXTENDED ' : 'EXPLAIN ') + select_sql
|
|
784
|
+
ds = db.send(:metadata_dataset).with_sql(sql.freeze).naked
|
|
784
785
|
rows = ds.all
|
|
785
786
|
Sequel::PrettyTable.string(rows, ds.columns)
|
|
786
787
|
end
|
|
@@ -339,7 +339,7 @@ module Sequel
|
|
|
339
339
|
end
|
|
340
340
|
|
|
341
341
|
def commit_prepared_transaction(transaction_id, opts=OPTS)
|
|
342
|
-
run("COMMIT PREPARED #{literal(transaction_id)}", opts)
|
|
342
|
+
run("COMMIT PREPARED #{literal(transaction_id)}".freeze, opts)
|
|
343
343
|
end
|
|
344
344
|
|
|
345
345
|
# A hash of metadata for CHECK constraints on the table.
|
|
@@ -416,7 +416,7 @@ module Sequel
|
|
|
416
416
|
return if already_identity
|
|
417
417
|
|
|
418
418
|
transaction(server_hash) do
|
|
419
|
-
run("ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{quote_identifier(column)} DROP DEFAULT", server_hash)
|
|
419
|
+
run("ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{quote_identifier(column)} DROP DEFAULT".freeze, server_hash)
|
|
420
420
|
|
|
421
421
|
ds.from(:pg_depend).
|
|
422
422
|
where(:classid=>pg_class, :objid=>seq_oid, :objsubid=>0, :deptype=>'a').
|
|
@@ -453,7 +453,7 @@ module Sequel
|
|
|
453
453
|
# often used here if :security_definer is used.
|
|
454
454
|
# :strict :: Makes the function return NULL when any argument is NULL.
|
|
455
455
|
def create_function(name, definition, opts=OPTS)
|
|
456
|
-
self << create_function_sql(name, definition, opts)
|
|
456
|
+
self << create_function_sql(name, definition, opts).freeze
|
|
457
457
|
end
|
|
458
458
|
|
|
459
459
|
# Create the procedural language in the database. Arguments:
|
|
@@ -464,7 +464,7 @@ module Sequel
|
|
|
464
464
|
# :trusted :: Marks the language being created as trusted, allowing unprivileged users to create functions using this language.
|
|
465
465
|
# :validator :: The name of previously registered function used as a validator of functions defined in this language.
|
|
466
466
|
def create_language(name, opts=OPTS)
|
|
467
|
-
self << create_language_sql(name, opts)
|
|
467
|
+
self << create_language_sql(name, opts).freeze
|
|
468
468
|
end
|
|
469
469
|
|
|
470
470
|
# Create a schema in the database. Arguments:
|
|
@@ -473,7 +473,7 @@ module Sequel
|
|
|
473
473
|
# :if_not_exists :: Don't raise an error if the schema already exists (PostgreSQL 9.3+)
|
|
474
474
|
# :owner :: The owner to set for the schema (defaults to current user if not specified)
|
|
475
475
|
def create_schema(name, opts=OPTS)
|
|
476
|
-
self << create_schema_sql(name, opts)
|
|
476
|
+
self << create_schema_sql(name, opts).freeze
|
|
477
477
|
end
|
|
478
478
|
|
|
479
479
|
# Support partitions of tables using the :partition_of option.
|
|
@@ -509,7 +509,7 @@ module Sequel
|
|
|
509
509
|
# :replace :: Replace the trigger with the same name if it already exists (PostgreSQL 14+).
|
|
510
510
|
# :when :: A filter to use for the trigger
|
|
511
511
|
def create_trigger(table, name, function, opts=OPTS)
|
|
512
|
-
self << create_trigger_sql(table, name, function, opts)
|
|
512
|
+
self << create_trigger_sql(table, name, function, opts).freeze
|
|
513
513
|
end
|
|
514
514
|
|
|
515
515
|
def database_type
|
|
@@ -542,7 +542,7 @@ module Sequel
|
|
|
542
542
|
# default is plpgsql. Can be specified as a string or a symbol.
|
|
543
543
|
def do(code, opts=OPTS)
|
|
544
544
|
language = opts[:language]
|
|
545
|
-
run "DO #{"LANGUAGE #{literal(language.to_s)} " if language}#{literal(code)}"
|
|
545
|
+
run "DO #{"LANGUAGE #{literal(language.to_s)} " if language}#{literal(code)}".freeze
|
|
546
546
|
end
|
|
547
547
|
|
|
548
548
|
# Drops the function from the database. Arguments:
|
|
@@ -552,7 +552,7 @@ module Sequel
|
|
|
552
552
|
# :cascade :: Drop other objects depending on this function.
|
|
553
553
|
# :if_exists :: Don't raise an error if the function doesn't exist.
|
|
554
554
|
def drop_function(name, opts=OPTS)
|
|
555
|
-
self << drop_function_sql(name, opts)
|
|
555
|
+
self << drop_function_sql(name, opts).freeze
|
|
556
556
|
end
|
|
557
557
|
|
|
558
558
|
# Drops a procedural language from the database. Arguments:
|
|
@@ -561,7 +561,7 @@ module Sequel
|
|
|
561
561
|
# :cascade :: Drop other objects depending on this function.
|
|
562
562
|
# :if_exists :: Don't raise an error if the function doesn't exist.
|
|
563
563
|
def drop_language(name, opts=OPTS)
|
|
564
|
-
self << drop_language_sql(name, opts)
|
|
564
|
+
self << drop_language_sql(name, opts).freeze
|
|
565
565
|
end
|
|
566
566
|
|
|
567
567
|
# Drops a schema from the database. Arguments:
|
|
@@ -570,7 +570,7 @@ module Sequel
|
|
|
570
570
|
# :cascade :: Drop all objects in this schema.
|
|
571
571
|
# :if_exists :: Don't raise an error if the schema doesn't exist.
|
|
572
572
|
def drop_schema(name, opts=OPTS)
|
|
573
|
-
self << drop_schema_sql(name, opts)
|
|
573
|
+
self << drop_schema_sql(name, opts).freeze
|
|
574
574
|
remove_all_cached_schemas
|
|
575
575
|
end
|
|
576
576
|
|
|
@@ -581,7 +581,7 @@ module Sequel
|
|
|
581
581
|
# :cascade :: Drop other objects depending on this function.
|
|
582
582
|
# :if_exists :: Don't raise an error if the function doesn't exist.
|
|
583
583
|
def drop_trigger(table, name, opts=OPTS)
|
|
584
|
-
self << drop_trigger_sql(table, name, opts)
|
|
584
|
+
self << drop_trigger_sql(table, name, opts).freeze
|
|
585
585
|
end
|
|
586
586
|
|
|
587
587
|
# Return full foreign key information using the pg system tables, including
|
|
@@ -745,7 +745,7 @@ module Sequel
|
|
|
745
745
|
# name :: Current name of the schema
|
|
746
746
|
# opts :: New name for the schema
|
|
747
747
|
def rename_schema(name, new_name)
|
|
748
|
-
self << rename_schema_sql(name, new_name)
|
|
748
|
+
self << rename_schema_sql(name, new_name).freeze
|
|
749
749
|
remove_all_cached_schemas
|
|
750
750
|
end
|
|
751
751
|
|
|
@@ -756,7 +756,7 @@ module Sequel
|
|
|
756
756
|
# DB.refresh_view(:items_view, concurrently: true)
|
|
757
757
|
# # REFRESH MATERIALIZED VIEW CONCURRENTLY items_view
|
|
758
758
|
def refresh_view(name, opts=OPTS)
|
|
759
|
-
run "REFRESH MATERIALIZED VIEW#{' CONCURRENTLY' if opts[:concurrently]} #{quote_schema_table(name)}"
|
|
759
|
+
run "REFRESH MATERIALIZED VIEW#{' CONCURRENTLY' if opts[:concurrently]} #{quote_schema_table(name)}".freeze
|
|
760
760
|
end
|
|
761
761
|
|
|
762
762
|
# Reset the primary key sequence for the given table, basing it on the
|
|
@@ -769,7 +769,7 @@ module Sequel
|
|
|
769
769
|
table = Sequel.qualify(s, t) if s
|
|
770
770
|
|
|
771
771
|
if server_version >= 100000
|
|
772
|
-
seq_ds = metadata_dataset.from(:pg_sequence).where(:seqrelid=>regclass_oid(LiteralString.new(seq)))
|
|
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
|
# :nocov:
|
|
@@ -784,7 +784,7 @@ module Sequel
|
|
|
784
784
|
end
|
|
785
785
|
|
|
786
786
|
def rollback_prepared_transaction(transaction_id, opts=OPTS)
|
|
787
|
-
run("ROLLBACK PREPARED #{literal(transaction_id)}", opts)
|
|
787
|
+
run("ROLLBACK PREPARED #{literal(transaction_id)}".freeze, opts)
|
|
788
788
|
end
|
|
789
789
|
|
|
790
790
|
# PostgreSQL uses SERIAL psuedo-type instead of AUTOINCREMENT for
|
|
@@ -1469,7 +1469,7 @@ module Sequel
|
|
|
1469
1469
|
|
|
1470
1470
|
def column_references_add_period(cols)
|
|
1471
1471
|
cols= cols.dup
|
|
1472
|
-
cols[-1] = Sequel.lit("PERIOD #{quote_identifier(cols[-1])}")
|
|
1472
|
+
cols[-1] = Sequel.lit("PERIOD #{quote_identifier(cols[-1])}".freeze)
|
|
1473
1473
|
cols
|
|
1474
1474
|
end
|
|
1475
1475
|
|
|
@@ -195,7 +195,7 @@ module Sequel
|
|
|
195
195
|
|
|
196
196
|
# Dataset used for parsing schema
|
|
197
197
|
def _parse_pragma_ds(table_name, opts)
|
|
198
|
-
metadata_dataset.with_sql("PRAGMA table_#{'x' if sqlite_version > 33100}info(?)", input_identifier_meth(opts[:dataset]).call(table_name))
|
|
198
|
+
metadata_dataset.with_sql("PRAGMA table_#{'x' if sqlite_version > 33100}info(?)".freeze, input_identifier_meth(opts[:dataset]).call(table_name))
|
|
199
199
|
end
|
|
200
200
|
|
|
201
201
|
# Run all alter_table commands in a transaction. This is technically only
|
|
@@ -407,7 +407,7 @@ module Sequel
|
|
|
407
407
|
def defined_columns_for(table)
|
|
408
408
|
cols = parse_pragma(table, OPTS)
|
|
409
409
|
cols.each do |c|
|
|
410
|
-
c[:default] = LiteralString.new(c[:default]) if c[:default]
|
|
410
|
+
c[:default] = LiteralString.new(c[:default]).freeze if c[:default]
|
|
411
411
|
c[:type] = c[:db_type]
|
|
412
412
|
end
|
|
413
413
|
cols
|
|
@@ -684,7 +684,7 @@ module Sequel
|
|
|
684
684
|
# Load the PrettyTable class, needed for explain output
|
|
685
685
|
Sequel.extension(:_pretty_table) unless defined?(Sequel::PrettyTable)
|
|
686
686
|
|
|
687
|
-
ds = db.send(:metadata_dataset).clone(:sql=>"EXPLAIN #{select_sql}")
|
|
687
|
+
ds = db.send(:metadata_dataset).clone(:sql=>"EXPLAIN #{select_sql}".freeze)
|
|
688
688
|
rows = ds.all
|
|
689
689
|
Sequel::PrettyTable.string(rows, ds.columns)
|
|
690
690
|
end
|
|
@@ -388,7 +388,7 @@ module Sequel
|
|
|
388
388
|
# SQLite uses a : before the name of the argument for named
|
|
389
389
|
# arguments.
|
|
390
390
|
def prepared_arg(k)
|
|
391
|
-
LiteralString.new("#{prepared_arg_placeholder}#{k.to_s.gsub('.', '__')}")
|
|
391
|
+
LiteralString.new("#{prepared_arg_placeholder}#{k.to_s.gsub('.', '__')}".freeze)
|
|
392
392
|
end
|
|
393
393
|
end
|
|
394
394
|
|
|
@@ -91,14 +91,16 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
91
91
|
# creates new connections to the database.
|
|
92
92
|
#
|
|
93
93
|
# If the :server option is provided, it should be a symbol or array of symbols,
|
|
94
|
-
# and then the method will only disconnect
|
|
94
|
+
# and then the method will only disconnect connections from those specified shards.
|
|
95
95
|
def disconnect(opts=OPTS)
|
|
96
96
|
(opts[:server] ? Array(opts[:server]) : sync{@servers.keys}).each do |server|
|
|
97
97
|
raise Sequel::Error, "invalid server" unless queue = sync{@queues[server]}
|
|
98
|
+
nconns = 0
|
|
98
99
|
while conn = available(queue, server)
|
|
100
|
+
nconns += 1
|
|
99
101
|
disconnect_pool_connection(conn, server)
|
|
100
102
|
end
|
|
101
|
-
fill_queue(server)
|
|
103
|
+
fill_queue(server, nconns)
|
|
102
104
|
end
|
|
103
105
|
nil
|
|
104
106
|
end
|
|
@@ -132,7 +134,7 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
132
134
|
conn = nil
|
|
133
135
|
disconnect_pool_connection(oconn, server) if oconn
|
|
134
136
|
sync{@allocated[server].delete(t)}
|
|
135
|
-
fill_queue(server)
|
|
137
|
+
fill_queue(server, 1)
|
|
136
138
|
end
|
|
137
139
|
raise
|
|
138
140
|
ensure
|
|
@@ -250,11 +252,15 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
250
252
|
# after disconnecting to potentially add new connections to the
|
|
251
253
|
# pool, so the threads that are currently waiting for connections
|
|
252
254
|
# do not timeout after the pool is no longer full.
|
|
253
|
-
|
|
255
|
+
#
|
|
256
|
+
# nconns specifies the maximum number of connections to add, which should
|
|
257
|
+
# be the number of connections that were disconnected.
|
|
258
|
+
def fill_queue(server, nconns)
|
|
254
259
|
queue = sync{@queues[server]}
|
|
255
|
-
if queue.num_waiting > 0
|
|
260
|
+
if nconns > 0 && queue.num_waiting > 0
|
|
256
261
|
Thread.new do
|
|
257
|
-
while queue.num_waiting > 0 && (conn = try_make_new(server))
|
|
262
|
+
while nconns > 0 && queue.num_waiting > 0 && (conn = try_make_new(server))
|
|
263
|
+
nconns -= 1
|
|
258
264
|
queue.push(conn)
|
|
259
265
|
end
|
|
260
266
|
end
|
|
@@ -303,7 +309,7 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
303
309
|
ensure
|
|
304
310
|
if to_disconnect
|
|
305
311
|
to_disconnect.each{|conn| disconnect_pool_connection(conn, server)}
|
|
306
|
-
fill_queue(server)
|
|
312
|
+
fill_queue(server, to_disconnect.size)
|
|
307
313
|
end
|
|
308
314
|
end
|
|
309
315
|
end
|
|
@@ -59,10 +59,12 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
59
59
|
# Once a connection is requested using #hold, the connection pool
|
|
60
60
|
# creates new connections to the database.
|
|
61
61
|
def disconnect(opts=OPTS)
|
|
62
|
+
nconns = 0
|
|
62
63
|
while conn = available
|
|
64
|
+
nconns += 1
|
|
63
65
|
disconnect_connection(conn)
|
|
64
66
|
end
|
|
65
|
-
fill_queue
|
|
67
|
+
fill_queue(nconns)
|
|
66
68
|
nil
|
|
67
69
|
end
|
|
68
70
|
|
|
@@ -94,7 +96,7 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
94
96
|
conn = nil
|
|
95
97
|
disconnect_connection(oconn) if oconn
|
|
96
98
|
sync{@allocated.delete(t)}
|
|
97
|
-
fill_queue
|
|
99
|
+
fill_queue(1)
|
|
98
100
|
end
|
|
99
101
|
raise
|
|
100
102
|
ensure
|
|
@@ -156,10 +158,13 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
156
158
|
# after disconnecting to potentially add new connections to the
|
|
157
159
|
# pool, so the threads that are currently waiting for connections
|
|
158
160
|
# do not timeout after the pool is no longer full.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
+
#
|
|
162
|
+
# nconns specifies the maximum number of connections to add, which should
|
|
163
|
+
# be the number of connections that were disconnected.
|
|
164
|
+
def fill_queue(nconns)
|
|
165
|
+
if nconns > 0 && @queue.num_waiting > 0
|
|
161
166
|
Thread.new do
|
|
162
|
-
while @queue.num_waiting > 0 && (conn = try_make_new)
|
|
167
|
+
while nconns > 0 && @queue.num_waiting > 0 && (conn = try_make_new)
|
|
163
168
|
@queue.push(conn)
|
|
164
169
|
end
|
|
165
170
|
end
|
|
@@ -207,7 +212,7 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
207
212
|
ensure
|
|
208
213
|
if to_disconnect
|
|
209
214
|
to_disconnect.each{|conn| disconnect_connection(conn)}
|
|
210
|
-
fill_queue
|
|
215
|
+
fill_queue(to_disconnect.size)
|
|
211
216
|
end
|
|
212
217
|
end
|
|
213
218
|
end
|
|
@@ -3,6 +3,33 @@
|
|
|
3
3
|
module Sequel
|
|
4
4
|
# The Schema module holds the schema generators.
|
|
5
5
|
module Schema
|
|
6
|
+
module ColumnOptionMerger
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
# Merge given options into the column's default options. For backwards compatibility,
|
|
10
|
+
# the options take priority, but in cases where the option value overrides the argument
|
|
11
|
+
# value, and the values are different, we warn as this is likely to be an error in the
|
|
12
|
+
# code.
|
|
13
|
+
def _merge_column_options(defaults, opts)
|
|
14
|
+
defaults.merge!(opts) do |k, defv, v|
|
|
15
|
+
unless defv == v
|
|
16
|
+
# :nocov:
|
|
17
|
+
if RUBY_VERSION >= "3.2"
|
|
18
|
+
# :nocov:
|
|
19
|
+
caller_loc = Thread.each_caller_location do |loc|
|
|
20
|
+
break loc unless loc.path == __FILE__
|
|
21
|
+
end
|
|
22
|
+
caller_loc &&= "#{caller_loc.path}:#{caller_loc.lineno}: "
|
|
23
|
+
end
|
|
24
|
+
warn("#{caller_loc}#{k.inspect} option value (#{v.inspect}) overrides argument value (#{defv.inspect})")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
v
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
private_constant :ColumnOptionMerger
|
|
32
|
+
|
|
6
33
|
# Schema::CreateTableGenerator is an internal class that the user is not expected
|
|
7
34
|
# to instantiate directly. Instances are created by Database#create_table.
|
|
8
35
|
# It is used to specify table creation parameters. It takes a Database
|
|
@@ -17,6 +44,8 @@ module Sequel
|
|
|
17
44
|
# For more information on Sequel's support for schema modification, see
|
|
18
45
|
# the {"Schema Modification" guide}[rdoc-ref:doc/schema_modification.rdoc].
|
|
19
46
|
class CreateTableGenerator
|
|
47
|
+
include ColumnOptionMerger
|
|
48
|
+
|
|
20
49
|
# Classes specifying generic types that Sequel will convert to database-specific types.
|
|
21
50
|
GENERIC_TYPES=%w'String Integer Float Numeric BigDecimal Date DateTime Time File TrueClass FalseClass'.freeze
|
|
22
51
|
|
|
@@ -173,13 +202,13 @@ module Sequel
|
|
|
173
202
|
# :clustered :: When using :primary_key or :unique, marks the primary key or unique
|
|
174
203
|
# constraint as CLUSTERED (if true), or NONCLUSTERED (if false).
|
|
175
204
|
def column(name, type, opts = OPTS)
|
|
176
|
-
columns << {:name => name, :type => type}
|
|
205
|
+
columns << _merge_column_options({:name => name, :type => type}, opts)
|
|
177
206
|
if index_opts = opts[:index]
|
|
178
207
|
index(name, index_opts.is_a?(Hash) ? index_opts : OPTS)
|
|
179
208
|
end
|
|
180
209
|
nil
|
|
181
210
|
end
|
|
182
|
-
|
|
211
|
+
|
|
183
212
|
# Adds a named CHECK constraint (or unnamed if name is nil),
|
|
184
213
|
# with the given block or args. To provide options for the constraint, pass
|
|
185
214
|
# a hash as the first argument.
|
|
@@ -246,7 +275,7 @@ module Sequel
|
|
|
246
275
|
opts.merge(:table=>table)
|
|
247
276
|
end
|
|
248
277
|
return composite_foreign_key(name, opts) if name.is_a?(Array)
|
|
249
|
-
column(name, Integer, opts)
|
|
278
|
+
column(name, opts.fetch(:type, Integer), opts)
|
|
250
279
|
end
|
|
251
280
|
|
|
252
281
|
# Add a full text index on the given columns.
|
|
@@ -429,6 +458,8 @@ module Sequel
|
|
|
429
458
|
# For more information on Sequel's support for schema modification, see
|
|
430
459
|
# the {"Schema Modification" guide}[link:files/doc/schema_modification_rdoc.html].
|
|
431
460
|
class AlterTableGenerator
|
|
461
|
+
include ColumnOptionMerger
|
|
462
|
+
|
|
432
463
|
# An array of operations to perform
|
|
433
464
|
attr_reader :operations
|
|
434
465
|
|
|
@@ -454,7 +485,7 @@ module Sequel
|
|
|
454
485
|
# :after :: The name of an existing column that the new column should be positioned after
|
|
455
486
|
# :first :: Create this new column before all other existing columns
|
|
456
487
|
def add_column(name, type, opts = OPTS)
|
|
457
|
-
op = {:op => :add_column, :name => name, :type => type}
|
|
488
|
+
op = _merge_column_options({:op => :add_column, :name => name, :type => type}, opts)
|
|
458
489
|
index_opts = op.delete(:index)
|
|
459
490
|
@operations << op
|
|
460
491
|
add_index(name, index_opts.is_a?(Hash) ? index_opts : OPTS) if index_opts
|
|
@@ -519,7 +550,7 @@ module Sequel
|
|
|
519
550
|
# sense when using an array of columns.
|
|
520
551
|
def add_foreign_key(name, table, opts = OPTS)
|
|
521
552
|
return add_composite_foreign_key(name, table, opts) if name.is_a?(Array)
|
|
522
|
-
add_column(name, Integer, {:table=>table}.merge!(opts))
|
|
553
|
+
add_column(name, opts.fetch(:type, Integer), {:table=>table}.merge!(opts))
|
|
523
554
|
end
|
|
524
555
|
|
|
525
556
|
# Add a full text index on the given columns.
|
|
@@ -819,7 +819,7 @@ module Sequel
|
|
|
819
819
|
# SELECT sql statement.
|
|
820
820
|
def create_table_as(name, sql, options)
|
|
821
821
|
sql = sql.sql if sql.is_a?(Sequel::Dataset)
|
|
822
|
-
run(create_table_as_sql(name, sql, options))
|
|
822
|
+
run(create_table_as_sql(name, sql, options).freeze)
|
|
823
823
|
end
|
|
824
824
|
|
|
825
825
|
# SQL statement for creating a table from the result of a SELECT statement.
|
|
@@ -117,6 +117,8 @@ module Sequel
|
|
|
117
117
|
frags << final_sql
|
|
118
118
|
prepared_sql << final_sql
|
|
119
119
|
|
|
120
|
+
frags.each(&:freeze)
|
|
121
|
+
frags.freeze
|
|
120
122
|
[prepared_sql, frags]
|
|
121
123
|
end
|
|
122
124
|
|
|
@@ -125,6 +127,7 @@ module Sequel
|
|
|
125
127
|
@argn = -1
|
|
126
128
|
@args = []
|
|
127
129
|
ds = yield self, dataset
|
|
130
|
+
ds.opts[:sql].freeze
|
|
128
131
|
sql = ds.clone(:placeholder_literalizer=>self).sql
|
|
129
132
|
|
|
130
133
|
last_offset = 0
|
|
@@ -54,7 +54,7 @@ module Sequel
|
|
|
54
54
|
|
|
55
55
|
# Set the bind arguments based on the hash and call super.
|
|
56
56
|
def call(bind_vars=OPTS, &block)
|
|
57
|
-
sql = prepared_sql
|
|
57
|
+
sql = prepared_sql.freeze
|
|
58
58
|
prepared_args.freeze
|
|
59
59
|
ps = bind(bind_vars)
|
|
60
60
|
ps.clone(:bind_arguments=>ps.map_to_prepared_args(ps.opts[:bind_vars]), :sql=>sql, :prepared_sql=>sql).run(&block)
|
|
@@ -223,7 +223,7 @@ module Sequel
|
|
|
223
223
|
# with the prepared SQL, to ensure the prepared_sql_type is respected.
|
|
224
224
|
def force_prepared_sql
|
|
225
225
|
if prepared_sql_type != prepared_type
|
|
226
|
-
with_sql(prepared_sql)
|
|
226
|
+
with_sql(prepared_sql.freeze)
|
|
227
227
|
else
|
|
228
228
|
self
|
|
229
229
|
end
|
|
@@ -287,7 +287,7 @@ module Sequel
|
|
|
287
287
|
|
|
288
288
|
def run(&block)
|
|
289
289
|
if @opts[:prepared_sql_frags]
|
|
290
|
-
sql = literal(Sequel::SQL::PlaceholderLiteralString.new(@opts[:prepared_sql_frags], @opts[:bind_arguments], false))
|
|
290
|
+
sql = literal(Sequel::SQL::PlaceholderLiteralString.new(@opts[:prepared_sql_frags], @opts[:bind_arguments], false)).freeze
|
|
291
291
|
clone(:prepared_sql_frags=>nil, :sql=>sql, :prepared_sql=>sql).run(&block)
|
|
292
292
|
else
|
|
293
293
|
super
|
|
@@ -320,6 +320,9 @@ module Sequel
|
|
|
320
320
|
end
|
|
321
321
|
|
|
322
322
|
prepared_args.freeze
|
|
323
|
+
frags.freeze
|
|
324
|
+
frags.each(&:freeze)
|
|
325
|
+
prepared_sql.freeze
|
|
323
326
|
clone(:prepared_sql_frags=>frags, :prepared_sql=>prepared_sql, :sql=>prepared_sql)
|
|
324
327
|
end
|
|
325
328
|
|
|
@@ -409,7 +412,7 @@ module Sequel
|
|
|
409
412
|
ps = ps.with_extend(EmulatePreparedStatementMethods)
|
|
410
413
|
ps.send(:emulated_prepared_statement, type, name, values)
|
|
411
414
|
else
|
|
412
|
-
sql = ps.prepared_sql
|
|
415
|
+
sql = ps.prepared_sql.freeze
|
|
413
416
|
ps.prepared_args.freeze
|
|
414
417
|
ps.clone(:prepared_sql=>sql, :sql=>sql)
|
|
415
418
|
end
|
data/lib/sequel/dataset/query.rb
CHANGED
|
@@ -1301,7 +1301,7 @@ module Sequel
|
|
|
1301
1301
|
# * truncate (if a TRUNCATE statement, with no arguments)
|
|
1302
1302
|
def with_sql(sql, *args)
|
|
1303
1303
|
if sql.is_a?(Symbol)
|
|
1304
|
-
sql = public_send(sql, *args)
|
|
1304
|
+
sql = public_send(sql, *args).freeze
|
|
1305
1305
|
else
|
|
1306
1306
|
sql = SQL::PlaceholderLiteralString.new(sql, args) unless args.empty?
|
|
1307
1307
|
end
|
|
@@ -1474,7 +1474,10 @@ module Sequel
|
|
|
1474
1474
|
def default_join_table_qualification
|
|
1475
1475
|
:symbol
|
|
1476
1476
|
end
|
|
1477
|
-
|
|
1477
|
+
|
|
1478
|
+
PAREN_WRAPPER = ["(".freeze, ")".freeze].freeze
|
|
1479
|
+
private_constant :PAREN_WRAPPER
|
|
1480
|
+
|
|
1478
1481
|
# SQL expression object based on the expr type. See +where+.
|
|
1479
1482
|
def filter_expr(expr = nil, &block)
|
|
1480
1483
|
expr = nil if expr == EMPTY_ARRAY
|
|
@@ -1495,7 +1498,7 @@ module Sequel
|
|
|
1495
1498
|
raise Error, "Invalid filter expression: #{expr.inspect}"
|
|
1496
1499
|
end
|
|
1497
1500
|
when LiteralString
|
|
1498
|
-
|
|
1501
|
+
SQL::PlaceholderLiteralString.new(PAREN_WRAPPER, [expr])
|
|
1499
1502
|
when Numeric, SQL::NumericExpression, SQL::StringExpression, Proc, String, Set
|
|
1500
1503
|
raise Error, "Invalid filter expression: #{expr.inspect}"
|
|
1501
1504
|
when TrueClass, FalseClass
|
data/lib/sequel/dataset/sql.rb
CHANGED
|
@@ -53,7 +53,7 @@ module Sequel
|
|
|
53
53
|
when String
|
|
54
54
|
case v
|
|
55
55
|
when LiteralString
|
|
56
|
-
sql
|
|
56
|
+
literal_literal_string_append(sql, v)
|
|
57
57
|
when SQL::Blob
|
|
58
58
|
literal_blob_append(sql, v)
|
|
59
59
|
else
|
|
@@ -1424,6 +1424,11 @@ module Sequel
|
|
|
1424
1424
|
v.to_s
|
|
1425
1425
|
end
|
|
1426
1426
|
|
|
1427
|
+
# Append string to SQL string.
|
|
1428
|
+
def literal_literal_string_append(sql, v)
|
|
1429
|
+
sql << v
|
|
1430
|
+
end
|
|
1431
|
+
|
|
1427
1432
|
# SQL fragment for nil
|
|
1428
1433
|
def literal_nil
|
|
1429
1434
|
"NULL"
|
|
@@ -82,12 +82,12 @@ module Sequel
|
|
|
82
82
|
DURATION_UNITS = [:years, :months, :days, :hours, :minutes, :seconds].freeze
|
|
83
83
|
DEF_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| s.to_s.freeze}).freeze
|
|
84
84
|
POSTGRES_DURATION_UNITS = DURATION_UNITS.zip([:years, :months, :days, :hours, :mins, :secs].map{|s| s.to_s.freeze}).freeze
|
|
85
|
-
MYSQL_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s.upcase[0...-1]).freeze}).freeze
|
|
86
|
-
MSSQL_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s[0...-1]).freeze}).freeze
|
|
85
|
+
MYSQL_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s.upcase[0...-1].freeze).freeze}).freeze
|
|
86
|
+
MSSQL_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s[0...-1].freeze).freeze}).freeze
|
|
87
87
|
H2_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| s.to_s[0...-1].freeze}).freeze
|
|
88
|
-
DERBY_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit("SQL_TSI_#{s.to_s.upcase[0...-1]}").freeze}).freeze
|
|
88
|
+
DERBY_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit("SQL_TSI_#{s.to_s.upcase[0...-1]}".freeze).freeze}).freeze
|
|
89
89
|
ACCESS_DURATION_UNITS = DURATION_UNITS.zip(%w'yyyy m d h n s'.map(&:freeze)).freeze
|
|
90
|
-
DB2_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s).freeze}).freeze
|
|
90
|
+
DB2_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s.freeze).freeze}).freeze
|
|
91
91
|
|
|
92
92
|
# Append the SQL fragment for the DateAdd expression to the SQL query.
|
|
93
93
|
def date_add_sql_append(sql, da)
|
|
@@ -107,7 +107,7 @@ module Sequel
|
|
|
107
107
|
placeholder = []
|
|
108
108
|
vals = []
|
|
109
109
|
each_valid_interval_unit(h, POSTGRES_DURATION_UNITS) do |value, sql_unit|
|
|
110
|
-
placeholder << "#{', ' unless placeholder.empty?}#{sql_unit} := "
|
|
110
|
+
placeholder << "#{', ' unless placeholder.empty?}#{sql_unit} := ".freeze
|
|
111
111
|
vals << value
|
|
112
112
|
end
|
|
113
113
|
interval = Sequel.function(:make_interval, Sequel.lit(placeholder, *vals)) unless vals.empty?
|
|
@@ -156,7 +156,7 @@ module Sequel
|
|
|
156
156
|
expr = Sequel.cast_string(expr) + ' 00:00:00'
|
|
157
157
|
end
|
|
158
158
|
each_valid_interval_unit(h, DERBY_DURATION_UNITS) do |value, sql_unit|
|
|
159
|
-
expr = Sequel.lit(["{fn timestampadd(#{sql_unit}, ", ", timestamp(", "))}"], value, expr)
|
|
159
|
+
expr = Sequel.lit(["{fn timestampadd(#{sql_unit}, ".freeze, ", timestamp(", "))}"], value, expr)
|
|
160
160
|
end
|
|
161
161
|
when :oracle
|
|
162
162
|
each_valid_interval_unit(h, MYSQL_DURATION_UNITS) do |value, sql_unit|
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
#
|
|
3
|
+
# The lit_require_frozen extension disallows the use of unfrozen strings
|
|
4
|
+
# as literal strings in database and dataset methods. If you try to use an
|
|
5
|
+
# unfrozen string as a literal string for a dataset using this extension,
|
|
6
|
+
# an exception will be raised.
|
|
7
|
+
#
|
|
8
|
+
# While this works for all Ruby versions, it is designed for use on Ruby 3+
|
|
9
|
+
# where all files are using the frozen-string-literal magic comment. In this
|
|
10
|
+
# case, uninterpolated literal strings are frozen, but interpolated strings
|
|
11
|
+
# are not frozen. This allows you to catch potentially dangerous code:
|
|
12
|
+
#
|
|
13
|
+
# # Probably safe, no exception raised
|
|
14
|
+
# DB["SELECT * FROM t WHERE c > :v", v: user_provided_string)
|
|
15
|
+
#
|
|
16
|
+
# # Potentially unsafe, raises Sequel::LitRequireFrozen::Error
|
|
17
|
+
# DB["SELECT * FROM t WHERE c > '#{user_provided_string}'"]
|
|
18
|
+
#
|
|
19
|
+
# The assumption made is that a frozen string is unlikely to contain unsafe
|
|
20
|
+
# input, while an unfrozen string has potentially been interpolated and may
|
|
21
|
+
# contain unsafe input.
|
|
22
|
+
#
|
|
23
|
+
# This disallows the the following cases:
|
|
24
|
+
#
|
|
25
|
+
# * Sequel::LiteralString instances that are unfrozen and are not based on a
|
|
26
|
+
# frozen string
|
|
27
|
+
# * Sequel::SQL::PlaceholderLiteralString instances when the placeholder string
|
|
28
|
+
# is not frozen
|
|
29
|
+
# * Unfrozen strings passed to Database#<< or #[] or Dataset#with_sql
|
|
30
|
+
#
|
|
31
|
+
# To use this extension, load it into the database:
|
|
32
|
+
#
|
|
33
|
+
# DB.extension :lit_require_frozen
|
|
34
|
+
#
|
|
35
|
+
# It can also be loaded into individual datasets:
|
|
36
|
+
#
|
|
37
|
+
# ds = DB[:t].extension(:lit_require_frozen)
|
|
38
|
+
#
|
|
39
|
+
# Assuming you have good test coverage, it is recommended to only load
|
|
40
|
+
# this extension when testing.
|
|
41
|
+
#
|
|
42
|
+
# Related module: Sequel::LitRequireFrozen
|
|
43
|
+
|
|
44
|
+
#
|
|
45
|
+
module Sequel
|
|
46
|
+
class LiteralString
|
|
47
|
+
# The string used when creating the literal string (first argument to
|
|
48
|
+
# Sequel::LiteralString.new). This may be nil if no string was provided,
|
|
49
|
+
# or if the litral string was created before this extension was required.
|
|
50
|
+
attr_reader :source
|
|
51
|
+
|
|
52
|
+
def initialize(*a)
|
|
53
|
+
@source = a.first
|
|
54
|
+
super
|
|
55
|
+
end
|
|
56
|
+
# :nocov:
|
|
57
|
+
ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
|
|
58
|
+
# :nocov:
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
module LitRequireFrozen
|
|
62
|
+
# Error class raised for using unfrozen literal string.
|
|
63
|
+
class Error < Sequel::Error
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
module DatabaseMethods
|
|
67
|
+
def self.extended(db)
|
|
68
|
+
db.extend_datasets(DatasetMethods)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Check given SQL is frozen before running it.
|
|
72
|
+
def run(sql, opts=OPTS)
|
|
73
|
+
@default_dataset.with_sql(sql)
|
|
74
|
+
super
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
module DatasetMethods
|
|
79
|
+
# Check given SQL is not an unfrozen string.
|
|
80
|
+
def with_sql(sql, *args)
|
|
81
|
+
_check_unfrozen_literal_string(sql)
|
|
82
|
+
super
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Check that placeholder string is frozen (or all entries
|
|
86
|
+
# in placeholder array are frozen).
|
|
87
|
+
def placeholder_literal_string_sql_append(sql, pls)
|
|
88
|
+
str = pls.str
|
|
89
|
+
|
|
90
|
+
if str.is_a?(Array)
|
|
91
|
+
str.each do |s|
|
|
92
|
+
_check_unfrozen_literal_string(s)
|
|
93
|
+
end
|
|
94
|
+
else
|
|
95
|
+
_check_unfrozen_literal_string(str)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
super
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
# Base method that other methods used to check for whether a string should be allowed
|
|
104
|
+
# as literal SQL. Allows non-strings as well as frozen strings.
|
|
105
|
+
def _check_unfrozen_literal_string(str)
|
|
106
|
+
return if !str.is_a?(String) || str.frozen?
|
|
107
|
+
|
|
108
|
+
if str.is_a?(LiteralString)
|
|
109
|
+
_check_unfrozen_literal_string(str.source)
|
|
110
|
+
else
|
|
111
|
+
raise Error, "cannot treat unfrozen string as literal SQL: #{str.inspect}"
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Check literal strings appended to SQL.
|
|
116
|
+
def literal_literal_string_append(sql, v)
|
|
117
|
+
_check_unfrozen_literal_string(v)
|
|
118
|
+
super
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Check static SQL is not frozen.
|
|
122
|
+
def static_sql(sql)
|
|
123
|
+
_check_unfrozen_literal_string(sql)
|
|
124
|
+
super
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
Dataset.register_extension(:lit_require_frozen, LitRequireFrozen::DatasetMethods)
|
|
130
|
+
Database.register_extension(:lit_require_frozen, LitRequireFrozen::DatabaseMethods)
|
|
131
|
+
end
|
|
@@ -186,22 +186,19 @@ module Sequel
|
|
|
186
186
|
# and returns a new block that reverses the actions taken by
|
|
187
187
|
# the given block.
|
|
188
188
|
def reverse(&block)
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
Proc.
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
send(*a, &pr)
|
|
203
|
-
end
|
|
204
|
-
end
|
|
189
|
+
instance_exec(&block)
|
|
190
|
+
rescue NoMethodError => e
|
|
191
|
+
Proc.new{raise Sequel::Error, "irreversible migration method \"#{e.name}\" used in #{block.source_location.first}, you may need to write your own down method"}
|
|
192
|
+
rescue => e
|
|
193
|
+
Proc.new{raise Sequel::Error, "unable to reverse migration due to #{e.class} in #{block.source_location.first}, you may need to write your own down method"}
|
|
194
|
+
else
|
|
195
|
+
actions = @actions.reverse
|
|
196
|
+
Proc.new do
|
|
197
|
+
actions.each do |a|
|
|
198
|
+
pr = a.last.is_a?(Proc) ? a.pop : nil
|
|
199
|
+
# Allow calling private methods as the reversing methods are private
|
|
200
|
+
send(*a, &pr)
|
|
201
|
+
end
|
|
205
202
|
end
|
|
206
203
|
end
|
|
207
204
|
|
|
@@ -270,7 +267,7 @@ module Sequel
|
|
|
270
267
|
end
|
|
271
268
|
|
|
272
269
|
def add_primary_key(*args)
|
|
273
|
-
|
|
270
|
+
super if args.first.is_a?(Array)
|
|
274
271
|
@actions << [:drop_column, args.first]
|
|
275
272
|
end
|
|
276
273
|
|
data/lib/sequel/plugins/dirty.rb
CHANGED
|
@@ -234,8 +234,11 @@ module Sequel
|
|
|
234
234
|
iv.delete(column)
|
|
235
235
|
end
|
|
236
236
|
else
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
if db_schema[column]
|
|
238
|
+
check_missing_initial_value(column)
|
|
239
|
+
iv[column] = get_column_value(column)
|
|
240
|
+
end
|
|
241
|
+
|
|
239
242
|
super
|
|
240
243
|
end
|
|
241
244
|
end
|
|
@@ -55,7 +55,7 @@ module Sequel
|
|
|
55
55
|
def _update_without_checking(columns)
|
|
56
56
|
ds = _update_dataset
|
|
57
57
|
lc = model.lock_column
|
|
58
|
-
rows = ds.clone(ds.send(:default_server_opts, :sql=>ds.output(nil, [Sequel[:inserted][lc]]).update_sql(columns))).all
|
|
58
|
+
rows = ds.clone(ds.send(:default_server_opts, :sql=>ds.output(nil, [Sequel[:inserted][lc]]).update_sql(columns).freeze)).all
|
|
59
59
|
values[lc] = rows.first[lc] unless rows.empty?
|
|
60
60
|
rows.length
|
|
61
61
|
end
|
|
@@ -99,7 +99,7 @@ module Sequel
|
|
|
99
99
|
# Add an RETURNING clause to fetch the updated xmin when updating the row.
|
|
100
100
|
def _update_without_checking(columns)
|
|
101
101
|
ds = _update_dataset
|
|
102
|
-
rows = ds.clone(ds.send(:default_server_opts, :sql=>ds.returning(:xmin).update_sql(columns))).all
|
|
102
|
+
rows = ds.clone(ds.send(:default_server_opts, :sql=>ds.returning(:xmin).update_sql(columns).freeze)).all
|
|
103
103
|
values[:xmin] = rows.first[:xmin] unless rows.empty?
|
|
104
104
|
rows.length
|
|
105
105
|
end
|
|
@@ -30,6 +30,15 @@ module Sequel
|
|
|
30
30
|
# Otherwise, it is possible that the default column accessors will take
|
|
31
31
|
# precedence.
|
|
32
32
|
#
|
|
33
|
+
# Note that use of an unsafe serialization method can result in an attack vector
|
|
34
|
+
# (potentially allowing remote code execution) if an attacker has the ability to
|
|
35
|
+
# store data directly in the underlying column. This would affect the marshal
|
|
36
|
+
# serialization format, and on older versions of Ruby, potentially the yaml and
|
|
37
|
+
# json serialization formats as well. It can also affect custom formats. You
|
|
38
|
+
# should ensure that attackers do not have access to store data directly in the
|
|
39
|
+
# underlying column when using this plugin (especially when using an unsafe
|
|
40
|
+
# serialization method).
|
|
41
|
+
#
|
|
33
42
|
# == Example
|
|
34
43
|
#
|
|
35
44
|
# # Require json if you plan to use it, as the plugin doesn't require it for you.
|
|
@@ -97,7 +106,7 @@ module Sequel
|
|
|
97
106
|
register_format(:marshal, lambda{|v| [Marshal.dump(v)].pack('m')},
|
|
98
107
|
lambda do |v|
|
|
99
108
|
# Handle unpacked marshalled data for backwards compat
|
|
100
|
-
v = v.unpack('m')[0] unless v
|
|
109
|
+
v = v.unpack('m')[0] unless v.start_with?("\x04\x08")
|
|
101
110
|
Marshal.load(v)
|
|
102
111
|
end)
|
|
103
112
|
register_format(:yaml, :to_yaml.to_proc, lambda{|s| YAML.load(s)})
|
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 = 103
|
|
10
10
|
|
|
11
11
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
|
12
12
|
# releases that fix regressions from previous versions.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sequel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.103.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeremy Evans
|
|
@@ -241,6 +241,7 @@ files:
|
|
|
241
241
|
- lib/sequel/extensions/inflector.rb
|
|
242
242
|
- lib/sequel/extensions/integer64.rb
|
|
243
243
|
- lib/sequel/extensions/is_distinct_from.rb
|
|
244
|
+
- lib/sequel/extensions/lit_require_frozen.rb
|
|
244
245
|
- lib/sequel/extensions/looser_typecasting.rb
|
|
245
246
|
- lib/sequel/extensions/migration.rb
|
|
246
247
|
- lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb
|