sequel 5.80.0 → 5.92.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 +9 -4
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/ibmdb.rb +1 -0
- data/lib/sequel/adapters/jdbc/db2.rb +2 -2
- data/lib/sequel/adapters/jdbc/derby.rb +3 -3
- data/lib/sequel/adapters/jdbc/h2.rb +2 -2
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -2
- data/lib/sequel/adapters/jdbc/jtds.rb +2 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +5 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +5 -5
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +6 -6
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -2
- data/lib/sequel/adapters/jdbc/sqlserver.rb +2 -2
- data/lib/sequel/adapters/jdbc.rb +8 -8
- data/lib/sequel/adapters/mysql2.rb +8 -1
- data/lib/sequel/adapters/shared/access.rb +1 -0
- data/lib/sequel/adapters/shared/db2.rb +1 -1
- data/lib/sequel/adapters/shared/mssql.rb +18 -5
- data/lib/sequel/adapters/shared/mysql.rb +8 -4
- data/lib/sequel/adapters/shared/oracle.rb +1 -0
- data/lib/sequel/adapters/shared/postgres.rb +106 -13
- data/lib/sequel/adapters/shared/sqlite.rb +4 -2
- data/lib/sequel/adapters/sqlite.rb +4 -0
- data/lib/sequel/adapters/trilogy.rb +1 -2
- data/lib/sequel/connection_pool/sharded_threaded.rb +26 -10
- data/lib/sequel/connection_pool/threaded.rb +26 -10
- data/lib/sequel/connection_pool.rb +2 -2
- data/lib/sequel/core.rb +15 -0
- data/lib/sequel/database/connecting.rb +20 -26
- data/lib/sequel/database/dataset_defaults.rb +3 -3
- data/lib/sequel/database/misc.rb +46 -10
- data/lib/sequel/database/query.rb +11 -11
- data/lib/sequel/database/schema_generator.rb +8 -0
- data/lib/sequel/database/schema_methods.rb +17 -1
- data/lib/sequel/dataset/actions.rb +9 -1
- data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +1 -1
- data/lib/sequel/dataset/prepared_statements.rb +2 -1
- data/lib/sequel/dataset/query.rb +9 -5
- data/lib/sequel/dataset/sql.rb +25 -5
- data/lib/sequel/extensions/caller_logging.rb +2 -0
- data/lib/sequel/extensions/connection_validator.rb +15 -10
- data/lib/sequel/extensions/dataset_run.rb +41 -0
- data/lib/sequel/extensions/migration.rb +23 -3
- data/lib/sequel/extensions/null_dataset.rb +2 -2
- data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -1
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +93 -10
- data/lib/sequel/extensions/pg_enum.rb +3 -3
- data/lib/sequel/extensions/pg_json_ops.rb +642 -9
- data/lib/sequel/extensions/pg_row.rb +3 -1
- data/lib/sequel/extensions/pg_schema_caching.rb +90 -0
- data/lib/sequel/extensions/provenance.rb +2 -0
- data/lib/sequel/extensions/query_blocker.rb +172 -0
- data/lib/sequel/extensions/schema_caching.rb +24 -9
- data/lib/sequel/extensions/schema_dumper.rb +16 -4
- data/lib/sequel/extensions/sqlite_json_ops.rb +1 -1
- data/lib/sequel/extensions/stdio_logger.rb +48 -0
- data/lib/sequel/extensions/string_agg.rb +17 -4
- data/lib/sequel/extensions/temporarily_release_connection.rb +178 -0
- data/lib/sequel/extensions/virtual_row_method_block.rb +1 -0
- data/lib/sequel/model/associations.rb +28 -3
- data/lib/sequel/model/base.rb +67 -18
- data/lib/sequel/plugins/association_pks.rb +1 -1
- data/lib/sequel/plugins/column_encryption.rb +1 -1
- data/lib/sequel/plugins/composition.rb +1 -1
- data/lib/sequel/plugins/defaults_setter.rb +16 -4
- data/lib/sequel/plugins/enum.rb +1 -1
- data/lib/sequel/plugins/forbid_lazy_load.rb +14 -1
- data/lib/sequel/plugins/input_transformer.rb +1 -1
- data/lib/sequel/plugins/inspect_pk.rb +44 -0
- data/lib/sequel/plugins/instance_filters.rb +4 -1
- data/lib/sequel/plugins/inverted_subsets.rb +1 -0
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +10 -5
- data/lib/sequel/plugins/optimistic_locking.rb +2 -0
- data/lib/sequel/plugins/paged_operations.rb +5 -2
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +6 -1
- data/lib/sequel/plugins/pg_auto_validate_enums.rb +88 -0
- data/lib/sequel/plugins/pg_eager_any_typed_array.rb +95 -0
- data/lib/sequel/plugins/rcte_tree.rb +1 -1
- data/lib/sequel/plugins/serialization.rb +11 -5
- data/lib/sequel/plugins/sql_comments.rb +7 -2
- data/lib/sequel/plugins/static_cache_cache.rb +50 -13
- data/lib/sequel/plugins/subset_conditions.rb +85 -5
- data/lib/sequel/plugins/subset_static_cache.rb +263 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +6 -2
- data/lib/sequel/plugins/validate_associated.rb +1 -1
- data/lib/sequel/sql.rb +16 -6
- data/lib/sequel/version.rb +1 -1
- metadata +12 -234
- data/CHANGELOG +0 -1355
- data/README.rdoc +0 -936
- data/doc/advanced_associations.rdoc +0 -884
- data/doc/association_basics.rdoc +0 -1859
- data/doc/bin_sequel.rdoc +0 -146
- data/doc/cheat_sheet.rdoc +0 -255
- data/doc/code_order.rdoc +0 -102
- data/doc/core_extensions.rdoc +0 -405
- data/doc/dataset_basics.rdoc +0 -96
- data/doc/dataset_filtering.rdoc +0 -222
- data/doc/extensions.rdoc +0 -77
- data/doc/fork_safety.rdoc +0 -84
- data/doc/mass_assignment.rdoc +0 -98
- data/doc/migration.rdoc +0 -660
- data/doc/model_dataset_method_design.rdoc +0 -129
- data/doc/model_hooks.rdoc +0 -254
- data/doc/model_plugins.rdoc +0 -270
- data/doc/mssql_stored_procedures.rdoc +0 -43
- data/doc/object_model.rdoc +0 -563
- data/doc/opening_databases.rdoc +0 -436
- data/doc/postgresql.rdoc +0 -611
- data/doc/prepared_statements.rdoc +0 -144
- data/doc/querying.rdoc +0 -1070
- data/doc/reflection.rdoc +0 -120
- data/doc/release_notes/5.0.0.txt +0 -159
- data/doc/release_notes/5.1.0.txt +0 -31
- data/doc/release_notes/5.10.0.txt +0 -84
- data/doc/release_notes/5.11.0.txt +0 -83
- data/doc/release_notes/5.12.0.txt +0 -141
- data/doc/release_notes/5.13.0.txt +0 -27
- data/doc/release_notes/5.14.0.txt +0 -63
- data/doc/release_notes/5.15.0.txt +0 -39
- data/doc/release_notes/5.16.0.txt +0 -110
- data/doc/release_notes/5.17.0.txt +0 -31
- data/doc/release_notes/5.18.0.txt +0 -69
- data/doc/release_notes/5.19.0.txt +0 -28
- data/doc/release_notes/5.2.0.txt +0 -33
- data/doc/release_notes/5.20.0.txt +0 -89
- data/doc/release_notes/5.21.0.txt +0 -87
- data/doc/release_notes/5.22.0.txt +0 -48
- data/doc/release_notes/5.23.0.txt +0 -56
- data/doc/release_notes/5.24.0.txt +0 -56
- data/doc/release_notes/5.25.0.txt +0 -32
- data/doc/release_notes/5.26.0.txt +0 -35
- data/doc/release_notes/5.27.0.txt +0 -21
- data/doc/release_notes/5.28.0.txt +0 -16
- data/doc/release_notes/5.29.0.txt +0 -22
- data/doc/release_notes/5.3.0.txt +0 -121
- data/doc/release_notes/5.30.0.txt +0 -20
- data/doc/release_notes/5.31.0.txt +0 -148
- data/doc/release_notes/5.32.0.txt +0 -46
- data/doc/release_notes/5.33.0.txt +0 -24
- data/doc/release_notes/5.34.0.txt +0 -40
- data/doc/release_notes/5.35.0.txt +0 -56
- data/doc/release_notes/5.36.0.txt +0 -60
- data/doc/release_notes/5.37.0.txt +0 -30
- data/doc/release_notes/5.38.0.txt +0 -28
- data/doc/release_notes/5.39.0.txt +0 -19
- data/doc/release_notes/5.4.0.txt +0 -80
- data/doc/release_notes/5.40.0.txt +0 -40
- data/doc/release_notes/5.41.0.txt +0 -25
- data/doc/release_notes/5.42.0.txt +0 -136
- data/doc/release_notes/5.43.0.txt +0 -98
- data/doc/release_notes/5.44.0.txt +0 -32
- data/doc/release_notes/5.45.0.txt +0 -34
- data/doc/release_notes/5.46.0.txt +0 -87
- data/doc/release_notes/5.47.0.txt +0 -59
- data/doc/release_notes/5.48.0.txt +0 -14
- data/doc/release_notes/5.49.0.txt +0 -59
- data/doc/release_notes/5.5.0.txt +0 -61
- data/doc/release_notes/5.50.0.txt +0 -78
- data/doc/release_notes/5.51.0.txt +0 -47
- data/doc/release_notes/5.52.0.txt +0 -87
- data/doc/release_notes/5.53.0.txt +0 -23
- data/doc/release_notes/5.54.0.txt +0 -27
- data/doc/release_notes/5.55.0.txt +0 -21
- data/doc/release_notes/5.56.0.txt +0 -51
- data/doc/release_notes/5.57.0.txt +0 -23
- data/doc/release_notes/5.58.0.txt +0 -31
- data/doc/release_notes/5.59.0.txt +0 -73
- data/doc/release_notes/5.6.0.txt +0 -31
- data/doc/release_notes/5.60.0.txt +0 -22
- data/doc/release_notes/5.61.0.txt +0 -43
- data/doc/release_notes/5.62.0.txt +0 -132
- data/doc/release_notes/5.63.0.txt +0 -33
- data/doc/release_notes/5.64.0.txt +0 -50
- data/doc/release_notes/5.65.0.txt +0 -21
- data/doc/release_notes/5.66.0.txt +0 -24
- data/doc/release_notes/5.67.0.txt +0 -32
- data/doc/release_notes/5.68.0.txt +0 -61
- data/doc/release_notes/5.69.0.txt +0 -26
- data/doc/release_notes/5.7.0.txt +0 -108
- data/doc/release_notes/5.70.0.txt +0 -35
- data/doc/release_notes/5.71.0.txt +0 -21
- data/doc/release_notes/5.72.0.txt +0 -33
- data/doc/release_notes/5.73.0.txt +0 -66
- data/doc/release_notes/5.74.0.txt +0 -45
- data/doc/release_notes/5.75.0.txt +0 -35
- data/doc/release_notes/5.76.0.txt +0 -86
- data/doc/release_notes/5.77.0.txt +0 -63
- data/doc/release_notes/5.78.0.txt +0 -67
- data/doc/release_notes/5.79.0.txt +0 -28
- data/doc/release_notes/5.8.0.txt +0 -170
- data/doc/release_notes/5.80.0.txt +0 -40
- data/doc/release_notes/5.9.0.txt +0 -99
- data/doc/schema_modification.rdoc +0 -679
- data/doc/security.rdoc +0 -443
- data/doc/sharding.rdoc +0 -286
- data/doc/sql.rdoc +0 -648
- data/doc/testing.rdoc +0 -190
- data/doc/thread_safety.rdoc +0 -15
- data/doc/transactions.rdoc +0 -250
- data/doc/validations.rdoc +0 -558
- data/doc/virtual_rows.rdoc +0 -265
@@ -430,6 +430,10 @@ module Sequel
|
|
430
430
|
# add_unique_constraint(:name, name: :unique_name) # ADD CONSTRAINT unique_name UNIQUE (name)
|
431
431
|
#
|
432
432
|
# Supports the same :deferrable option as CreateTableGenerator#column.
|
433
|
+
#
|
434
|
+
# PostgreSQL specific options:
|
435
|
+
#
|
436
|
+
# :using_index :: Use the USING INDEX clause to specify an existing unique index
|
433
437
|
def add_unique_constraint(columns, opts = OPTS)
|
434
438
|
@operations << {:op => :add_constraint, :type => :unique, :columns => Array(columns)}.merge!(opts)
|
435
439
|
nil
|
@@ -483,6 +487,10 @@ module Sequel
|
|
483
487
|
#
|
484
488
|
# add_primary_key(:id) # ADD COLUMN id serial PRIMARY KEY
|
485
489
|
# add_primary_key([:artist_id, :name]) # ADD PRIMARY KEY (artist_id, name)
|
490
|
+
#
|
491
|
+
# PostgreSQL specific options:
|
492
|
+
#
|
493
|
+
# :using_index :: Use the USING INDEX clause to specify an existing unique index
|
486
494
|
def add_primary_key(name, opts = OPTS)
|
487
495
|
return add_composite_primary_key(name, opts) if name.is_a?(Array)
|
488
496
|
opts = @db.serial_primary_key_options.merge(opts)
|
@@ -191,6 +191,8 @@ module Sequel
|
|
191
191
|
# The +any+ type is treated like a SQLite column in a non-strict table,
|
192
192
|
# allowing any type of data to be stored. This option is supported on
|
193
193
|
# SQLite 3.37.0+.
|
194
|
+
# :using :: Create a VIRTUAL table with the given USING clause. The value should be
|
195
|
+
# a string, as it is used directly in the SQL query.
|
194
196
|
# :without_rowid :: Create a WITHOUT ROWID table. Every row in SQLite has a special
|
195
197
|
# 'rowid' column, that uniquely identifies that row within the table.
|
196
198
|
# If this option is used, the 'rowid' column is omitted, which can
|
@@ -775,7 +777,21 @@ module Sequel
|
|
775
777
|
|
776
778
|
# SQL fragment for initial part of CREATE TABLE statement
|
777
779
|
def create_table_prefix_sql(name, options)
|
778
|
-
"CREATE #{temporary_table_sql if options[:temp]}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{
|
780
|
+
"CREATE #{temporary_table_sql if options[:temp]}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{create_table_table_name_sql(name, options)}"
|
781
|
+
end
|
782
|
+
|
783
|
+
# The SQL to use for a table name when creating a table.
|
784
|
+
# Use of the :temp option can result in different SQL,
|
785
|
+
# because the rules for temp table naming can differ
|
786
|
+
# between databases, and temp tables should not use the
|
787
|
+
# default_schema.
|
788
|
+
def create_table_table_name_sql(name, options)
|
789
|
+
options[:temp] ? create_table_temp_table_name_sql(name, options) : quote_schema_table(name)
|
790
|
+
end
|
791
|
+
|
792
|
+
# The SQL to use for the table name for a temporary table.
|
793
|
+
def create_table_temp_table_name_sql(name, _options)
|
794
|
+
name.is_a?(String) ? quote_identifier(name) : literal(name)
|
779
795
|
end
|
780
796
|
|
781
797
|
# SQL fragment for initial part of CREATE VIEW statement
|
@@ -217,7 +217,7 @@ module Sequel
|
|
217
217
|
case args.length
|
218
218
|
when 0
|
219
219
|
unless block
|
220
|
-
return single_record
|
220
|
+
return(@opts[:sql] ? single_record! : single_record)
|
221
221
|
end
|
222
222
|
when 1
|
223
223
|
arg = args[0]
|
@@ -282,6 +282,12 @@ module Sequel
|
|
282
282
|
#
|
283
283
|
# DB[:table].get{[sum(id).as(sum), name]} # SELECT sum(id) AS sum, name FROM table LIMIT 1
|
284
284
|
# # => [6, 'foo']
|
285
|
+
#
|
286
|
+
# If called on a dataset with raw SQL, returns the
|
287
|
+
# first value in the dataset without changing the selection or setting a limit:
|
288
|
+
#
|
289
|
+
# DB["SELECT id FROM table"].get # SELECT id FROM table
|
290
|
+
# # => 3
|
285
291
|
def get(column=(no_arg=true; nil), &block)
|
286
292
|
ds = naked
|
287
293
|
if block
|
@@ -289,6 +295,8 @@ module Sequel
|
|
289
295
|
ds = ds.select(&block)
|
290
296
|
column = ds.opts[:select]
|
291
297
|
column = nil if column.is_a?(Array) && column.length < 2
|
298
|
+
elsif no_arg && opts[:sql]
|
299
|
+
return ds.single_value!
|
292
300
|
else
|
293
301
|
case column
|
294
302
|
when Array
|
@@ -19,7 +19,7 @@ module Sequel
|
|
19
19
|
def with_extend(*mods, &block)
|
20
20
|
c = _clone(:freeze=>false)
|
21
21
|
c.extend(*mods) unless mods.empty?
|
22
|
-
c.extend(DatasetModule.new(&block)) if block
|
22
|
+
c.extend(Sequel.set_temp_name(DatasetModule.new(&block)){"Sequel::Dataset::_DatasetModule(#{block.source_location.join(':')})"}) if block
|
23
23
|
c.freeze
|
24
24
|
end
|
25
25
|
|
@@ -20,7 +20,8 @@ module Sequel
|
|
20
20
|
def self.prepared_statements_module(code, mods, meths=DEFAULT_PREPARED_STATEMENT_MODULE_METHODS, &block)
|
21
21
|
code = PREPARED_STATEMENT_MODULE_CODE[code] || code
|
22
22
|
|
23
|
-
Module.new do
|
23
|
+
Module.new do
|
24
|
+
Sequel.set_temp_name(self){"Sequel::Dataset::_PreparedStatementsModule(#{block.source_location.join(':') if block})"}
|
24
25
|
Array(mods).each do |mod|
|
25
26
|
include mod
|
26
27
|
end
|
data/lib/sequel/dataset/query.rb
CHANGED
@@ -204,7 +204,7 @@ module Sequel
|
|
204
204
|
# If no related extension file exists or the extension does not have
|
205
205
|
# specific support for Dataset objects, an error will be raised.
|
206
206
|
def extension(*exts)
|
207
|
-
Sequel.extension(
|
207
|
+
exts.each{|ext| Sequel.extension(ext) unless Sequel.synchronize{EXTENSIONS[ext]}}
|
208
208
|
mods = exts.map{|ext| Sequel.synchronize{EXTENSION_MODULES[ext]}}
|
209
209
|
if mods.all?
|
210
210
|
with_extend(*mods)
|
@@ -1238,9 +1238,9 @@ module Sequel
|
|
1238
1238
|
# Note that like Object#extend, when multiple modules are provided
|
1239
1239
|
# as arguments the subclass includes the modules in reverse order.
|
1240
1240
|
def with_extend(*mods, &block)
|
1241
|
-
c = Class.new(self.class)
|
1241
|
+
c = Sequel.set_temp_name(Class.new(self.class)){"Sequel::Dataset::_Subclass"}
|
1242
1242
|
c.include(*mods) unless mods.empty?
|
1243
|
-
c.include(DatasetModule.new(&block)) if block
|
1243
|
+
c.include(Sequel.set_temp_name(DatasetModule.new(&block)){"Sequel::Dataset::_DatasetModule(#{block.source_location[0,2].join(':')})"}) if block
|
1244
1244
|
o = c.freeze.allocate
|
1245
1245
|
o.instance_variable_set(:@db, @db)
|
1246
1246
|
o.instance_variable_set(:@opts, @opts)
|
@@ -1359,9 +1359,13 @@ module Sequel
|
|
1359
1359
|
unless TRUE_FREEZE
|
1360
1360
|
# Load the extensions into the receiver, without checking if the receiver is frozen.
|
1361
1361
|
def _extension!(exts)
|
1362
|
-
Sequel.extension(*exts)
|
1363
1362
|
exts.each do |ext|
|
1364
|
-
|
1363
|
+
unless pr = Sequel.synchronize{EXTENSIONS[ext]}
|
1364
|
+
Sequel.extension(ext)
|
1365
|
+
pr = Sequel.synchronize{EXTENSIONS[ext]}
|
1366
|
+
end
|
1367
|
+
|
1368
|
+
if pr
|
1365
1369
|
pr.call(self)
|
1366
1370
|
else
|
1367
1371
|
raise(Error, "Extension #{ext} does not have specific support handling individual datasets (try: Sequel.extension #{ext.inspect})")
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -901,18 +901,31 @@ module Sequel
|
|
901
901
|
MERGE_TYPE_SQL = {
|
902
902
|
:insert => ' WHEN NOT MATCHED',
|
903
903
|
:delete => ' WHEN MATCHED',
|
904
|
+
:delete_not_matched_by_source => ' WHEN NOT MATCHED BY SOURCE',
|
904
905
|
:update => ' WHEN MATCHED',
|
906
|
+
:update_not_matched_by_source => ' WHEN NOT MATCHED BY SOURCE',
|
905
907
|
:matched => ' WHEN MATCHED',
|
906
908
|
:not_matched => ' WHEN NOT MATCHED',
|
909
|
+
:not_matched_by_source => ' WHEN NOT MATCHED BY SOURCE',
|
907
910
|
}.freeze
|
908
911
|
private_constant :MERGE_TYPE_SQL
|
909
912
|
|
913
|
+
MERGE_NORMALIZE_TYPE_MAP = {
|
914
|
+
:delete_not_matched_by_source => :delete,
|
915
|
+
:update_not_matched_by_source => :update,
|
916
|
+
:matched => :do_nothing,
|
917
|
+
:not_matched => :do_nothing,
|
918
|
+
:not_matched_by_source => :do_nothing,
|
919
|
+
}.freeze
|
920
|
+
private_constant :MERGE_NORMALIZE_TYPE_MAP
|
921
|
+
|
910
922
|
# Add the WHEN clauses to the MERGE SQL
|
911
923
|
def _merge_when_sql(sql)
|
912
924
|
raise Error, "no WHEN [NOT] MATCHED clauses provided for MERGE" unless merge_when = @opts[:merge_when]
|
913
925
|
merge_when.each do |data|
|
914
926
|
type = data[:type]
|
915
927
|
sql << MERGE_TYPE_SQL[type]
|
928
|
+
type = MERGE_NORMALIZE_TYPE_MAP[type] || type
|
916
929
|
_merge_when_conditions_sql(sql, data)
|
917
930
|
send(:"_merge_#{type}_sql", sql, data)
|
918
931
|
end
|
@@ -1019,7 +1032,7 @@ module Sequel
|
|
1019
1032
|
if column_aliases
|
1020
1033
|
raise Error, "#{db.database_type} does not support derived column lists" unless supports_derived_column_lists?
|
1021
1034
|
sql << '('
|
1022
|
-
|
1035
|
+
derived_column_list_sql_append(sql, column_aliases)
|
1023
1036
|
sql << ')'
|
1024
1037
|
end
|
1025
1038
|
end
|
@@ -1152,6 +1165,11 @@ module Sequel
|
|
1152
1165
|
end
|
1153
1166
|
end
|
1154
1167
|
|
1168
|
+
# Append the column aliases to the SQL.
|
1169
|
+
def derived_column_list_sql_append(sql, column_aliases)
|
1170
|
+
identifier_list_append(sql, column_aliases)
|
1171
|
+
end
|
1172
|
+
|
1155
1173
|
# Disable caching of SQL for the current dataset
|
1156
1174
|
def disable_sql_caching!
|
1157
1175
|
cache_set(:_no_cache_sql, true)
|
@@ -1412,10 +1430,6 @@ module Sequel
|
|
1412
1430
|
# calls +sql_literal+ if object responds to it, otherwise raises an error.
|
1413
1431
|
# If a database specific type is allowed, this should be overriden in a subclass.
|
1414
1432
|
def literal_other_append(sql, v)
|
1415
|
-
# We can't be sure if v will always literalize to the same SQL, so
|
1416
|
-
# don't cache SQL for a dataset that uses this.
|
1417
|
-
disable_sql_caching!
|
1418
|
-
|
1419
1433
|
if v.respond_to?(:sql_literal_append)
|
1420
1434
|
v.sql_literal_append(self, sql)
|
1421
1435
|
elsif v.respond_to?(:sql_literal)
|
@@ -1423,6 +1437,12 @@ module Sequel
|
|
1423
1437
|
else
|
1424
1438
|
raise Error, "can't express #{v.inspect} as a SQL literal"
|
1425
1439
|
end
|
1440
|
+
|
1441
|
+
if !v.respond_to?(:sql_literal_allow_caching?) || !v.sql_literal_allow_caching?(self)
|
1442
|
+
# We can't be sure if v will always literalize to the same SQL, so
|
1443
|
+
# don't cache SQL for a dataset that uses this.
|
1444
|
+
disable_sql_caching!
|
1445
|
+
end
|
1426
1446
|
end
|
1427
1447
|
|
1428
1448
|
# SQL fragment for Sequel::SQLTime, containing just the time part
|
@@ -37,6 +37,7 @@ module Sequel
|
|
37
37
|
module CallerLogging
|
38
38
|
SEQUEL_LIB_PATH = (File.expand_path('../../..', __FILE__) + '/').freeze
|
39
39
|
RUBY_STDLIB = RbConfig::CONFIG["rubylibdir"]
|
40
|
+
INTERNAL = '<internal'
|
40
41
|
|
41
42
|
# A regexp of caller lines to ignore, in addition to internal Sequel and Ruby code.
|
42
43
|
attr_accessor :caller_logging_ignore
|
@@ -61,6 +62,7 @@ module Sequel
|
|
61
62
|
c = caller.find do |line|
|
62
63
|
!(line.start_with?(SEQUEL_LIB_PATH) ||
|
63
64
|
line.start_with?(RUBY_STDLIB) ||
|
65
|
+
line.start_with?(INTERNAL) ||
|
64
66
|
(ignore && line =~ ignore))
|
65
67
|
end
|
66
68
|
|
@@ -105,18 +105,23 @@ module Sequel
|
|
105
105
|
1.times do
|
106
106
|
if (conn = super) &&
|
107
107
|
(timer = sync{@connection_timestamps.delete(conn)}) &&
|
108
|
-
Sequel.elapsed_seconds_since(timer) > @connection_validation_timeout
|
109
|
-
!db.valid_connection?(conn)
|
108
|
+
Sequel.elapsed_seconds_since(timer) > @connection_validation_timeout
|
110
109
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
110
|
+
begin
|
111
|
+
valid = db.valid_connection?(conn)
|
112
|
+
ensure
|
113
|
+
unless valid
|
114
|
+
case pool_type
|
115
|
+
when :sharded_threaded, :sharded_timed_queue
|
116
|
+
sync{@allocated[a.last].delete(Sequel.current)}
|
117
|
+
else
|
118
|
+
sync{@allocated.delete(Sequel.current)}
|
119
|
+
end
|
117
120
|
|
118
|
-
|
119
|
-
|
121
|
+
disconnect_connection(conn)
|
122
|
+
redo if valid == false
|
123
|
+
end
|
124
|
+
end
|
120
125
|
end
|
121
126
|
end
|
122
127
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
#
|
3
|
+
# The dataset_run extension is designed for cases where you want
|
4
|
+
# to use dataset methods to build a query, but want to run that
|
5
|
+
# query without returning a result. The most common need would
|
6
|
+
# be to easily use placeholders in an SQL string, which Database#run
|
7
|
+
# does not support directly.
|
8
|
+
#
|
9
|
+
# You can load this extension into specific datasets:
|
10
|
+
#
|
11
|
+
# ds = DB["GRANT SELECT ON ? TO ?", :table, :user]
|
12
|
+
# ds = ds.extension(:dataset_run)
|
13
|
+
# ds.run
|
14
|
+
#
|
15
|
+
# Or you can load it into all of a database's datasets, which
|
16
|
+
# is probably the desired behavior if you are using this extension:
|
17
|
+
#
|
18
|
+
# DB.extension(:dataset_run)
|
19
|
+
# DB["GRANT SELECT ON ? TO ?", :table, :user].run
|
20
|
+
#
|
21
|
+
# Related module: Sequel::DatasetRun
|
22
|
+
|
23
|
+
#
|
24
|
+
module Sequel
|
25
|
+
module DatasetRun
|
26
|
+
# Run the dataset's SQL on the database. Returns NULL. This is
|
27
|
+
# useful when you want to run SQL without returning a result.
|
28
|
+
#
|
29
|
+
# DB["GRANT SELECT ON ? TO ?", :table, :user].run
|
30
|
+
# # GRANT SELECT ON "table" TO "user"
|
31
|
+
def run
|
32
|
+
if server = @opts[:server]
|
33
|
+
db.run(sql, :server=>server)
|
34
|
+
else
|
35
|
+
db.run(sql)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Dataset.register_extension(:dataset_run, DatasetRun)
|
41
|
+
end
|
@@ -223,7 +223,7 @@ module Sequel
|
|
223
223
|
@actions << [:drop_join_table, *args]
|
224
224
|
end
|
225
225
|
|
226
|
-
def create_table(name, opts=OPTS)
|
226
|
+
def create_table(name, opts=OPTS, &_)
|
227
227
|
@actions << [:drop_table, name, opts]
|
228
228
|
end
|
229
229
|
|
@@ -287,6 +287,10 @@ module Sequel
|
|
287
287
|
def set_column_allow_null(name, allow_null=true)
|
288
288
|
@actions << [:set_column_allow_null, name, !allow_null]
|
289
289
|
end
|
290
|
+
|
291
|
+
def set_column_not_null(name)
|
292
|
+
@actions << [:set_column_allow_null, name]
|
293
|
+
end
|
290
294
|
end
|
291
295
|
|
292
296
|
# The preferred method for writing Sequel migrations, using a DSL:
|
@@ -371,7 +375,7 @@ module Sequel
|
|
371
375
|
#
|
372
376
|
# Part of the +migration+ extension.
|
373
377
|
class Migrator
|
374
|
-
MIGRATION_FILE_PATTERN = /\A(\d+)_
|
378
|
+
MIGRATION_FILE_PATTERN = /\A(\d+)_(.+)\.rb\z/i.freeze
|
375
379
|
|
376
380
|
# Mutex used around migration file loading
|
377
381
|
MUTEX = Mutex.new
|
@@ -791,7 +795,23 @@ module Sequel
|
|
791
795
|
next unless MIGRATION_FILE_PATTERN.match(file)
|
792
796
|
files << File.join(directory, file)
|
793
797
|
end
|
794
|
-
files.
|
798
|
+
files.sort! do |a, b|
|
799
|
+
a_ver, a_name = split_migration_filename(a)
|
800
|
+
b_ver, b_name = split_migration_filename(b)
|
801
|
+
x = a_ver <=> b_ver
|
802
|
+
if x.zero?
|
803
|
+
x = a_name <=> b_name
|
804
|
+
end
|
805
|
+
x
|
806
|
+
end
|
807
|
+
files
|
808
|
+
end
|
809
|
+
|
810
|
+
# Return an integer and name (without extension) for the given path.
|
811
|
+
def split_migration_filename(path)
|
812
|
+
version, name = MIGRATION_FILE_PATTERN.match(File.basename(path)).captures
|
813
|
+
version = version.to_i
|
814
|
+
[version, name]
|
795
815
|
end
|
796
816
|
|
797
817
|
# Returns tuples of migration, filename, and direction
|
@@ -63,12 +63,12 @@ module Sequel
|
|
63
63
|
end
|
64
64
|
|
65
65
|
# Return self without sending a database query, never yielding.
|
66
|
-
def each
|
66
|
+
def each(&_)
|
67
67
|
self
|
68
68
|
end
|
69
69
|
|
70
70
|
# Return nil without sending a database query, never yielding.
|
71
|
-
def fetch_rows(sql)
|
71
|
+
def fetch_rows(sql, &_)
|
72
72
|
nil
|
73
73
|
end
|
74
74
|
|
@@ -394,7 +394,7 @@ module Sequel
|
|
394
394
|
# there can be more than one parameter per column, so this doesn't prevent going
|
395
395
|
# over the limit, though it does make it less likely.
|
396
396
|
def default_import_slice
|
397
|
-
40
|
397
|
+
@opts[:no_auto_parameterize] ? super : 40
|
398
398
|
end
|
399
399
|
|
400
400
|
# Handle parameterization of multi_insert_sql
|
@@ -21,15 +21,26 @@
|
|
21
21
|
# DateTime :: timestamp (or timestamptz if pg_timestamptz extension is used)
|
22
22
|
# Sequel::SQLTime :: time
|
23
23
|
# Sequel::SQL::Blob :: bytea
|
24
|
+
#
|
25
|
+
# Arrays of string values are not automatically converted by default, because the Ruby
|
26
|
+
# String class can represent a number of different database types. To convert
|
27
|
+
# arrays of Ruby strings to an untyped array (a query parameter with no explicit
|
28
|
+
# type cast), set the +:treat_string_list_as_untyped_array+ Database option
|
29
|
+
# before loading the extension.
|
24
30
|
#
|
25
|
-
#
|
26
|
-
# +:treat_string_list_as_text_array+ Database option is used. This
|
27
|
-
#
|
28
|
-
#
|
31
|
+
# If you will only be using arrays of Ruby strings that represent the +text+ type,
|
32
|
+
# you can use the +:treat_string_list_as_text_array+ Database option is used. This
|
33
|
+
# can break programs, since the type for literal strings in PostgreSQL is +unknown+,
|
34
|
+
# not +text+.
|
29
35
|
#
|
30
|
-
# The conversion is only done for single dimensional arrays that have
|
31
|
-
#
|
32
|
-
# nil values).
|
36
|
+
# The conversion is only done for single dimensional arrays that have two or
|
37
|
+
# more elements, where all elements are of the same class (other than
|
38
|
+
# +nil+ values). You can also do the conversion for arrays of 1 element by setting
|
39
|
+
# <tt>pg_auto_parameterize_min_array_size: 1</tt> Database option. This makes
|
40
|
+
# finding cases that need special handling easier, but it doesn't match
|
41
|
+
# how PostgreSQL internally converts the expression (PostgreSQL converts
|
42
|
+
# <tt>IN (single_value)</tt> to <tt>= single_value</tt>, not
|
43
|
+
# <tt>= ANY(ARRAY[single_value])</tt>).
|
33
44
|
#
|
34
45
|
# Related module: Sequel::Postgres::AutoParameterizeInArray
|
35
46
|
|
@@ -37,6 +48,47 @@ module Sequel
|
|
37
48
|
module Postgres
|
38
49
|
# Enable automatically parameterizing queries.
|
39
50
|
module AutoParameterizeInArray
|
51
|
+
module TreatStringListAsUntypedArray
|
52
|
+
# Sentinal value to use as an auto param type to use auto parameterization
|
53
|
+
# of a string array without an explicit type cast.
|
54
|
+
NO_EXPLICIT_CAST = Object.new.freeze
|
55
|
+
|
56
|
+
# Wrapper for untyped PGArray values that will be parameterized directly
|
57
|
+
# into the query. This should only be used in cases where you know the
|
58
|
+
# value should be added as a query parameter.
|
59
|
+
class ParameterizedUntypedPGArray < SQL::Wrapper
|
60
|
+
def to_s_append(ds, sql)
|
61
|
+
sql.add_arg(@value)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# Recognize NO_EXPLICIT_CAST sentinal value and use wrapped
|
68
|
+
# PGArray that will be parameterized into the query.
|
69
|
+
def _convert_array_to_pg_array_with_type(r, type)
|
70
|
+
if NO_EXPLICIT_CAST.equal?(type)
|
71
|
+
ParameterizedUntypedPGArray.new(Sequel.pg_array(r))
|
72
|
+
else
|
73
|
+
super
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Use a query parameter with no type cast for string arrays.
|
78
|
+
def _bound_variable_type_for_string_array(r)
|
79
|
+
NO_EXPLICIT_CAST
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
module TreatStringListAsTextArray
|
84
|
+
private
|
85
|
+
|
86
|
+
# Assume all string arrays used on RHS of IN/NOT IN are for type text[]
|
87
|
+
def _bound_variable_type_for_string_array(r)
|
88
|
+
"text"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
40
92
|
# Transform column IN (...) expressions into column = ANY($)
|
41
93
|
# and column NOT IN (...) expressions into column != ALL($)
|
42
94
|
# using an array bound variable for the ANY/ALL argument,
|
@@ -56,7 +108,7 @@ module Sequel
|
|
56
108
|
op = :!=
|
57
109
|
func = :ALL
|
58
110
|
end
|
59
|
-
args = [l, Sequel.function(func,
|
111
|
+
args = [l, Sequel.function(func, _convert_array_to_pg_array_with_type(r, type))]
|
60
112
|
end
|
61
113
|
end
|
62
114
|
|
@@ -68,7 +120,7 @@ module Sequel
|
|
68
120
|
# The bound variable type string to use for the bound variable array.
|
69
121
|
# Returns nil if a bound variable should not be used for the array.
|
70
122
|
def _bound_variable_type_for_array(r)
|
71
|
-
return unless Array === r && r.size
|
123
|
+
return unless Array === r && r.size >= pg_auto_parameterize_min_array_size
|
72
124
|
classes = r.map(&:class)
|
73
125
|
classes.uniq!
|
74
126
|
classes.delete(NilClass)
|
@@ -81,7 +133,7 @@ module Sequel
|
|
81
133
|
# arrays natively (though the SQL used is different)
|
82
134
|
"int8"
|
83
135
|
elsif klass == String
|
84
|
-
|
136
|
+
_bound_variable_type_for_string_array(r)
|
85
137
|
elsif klass == BigDecimal
|
86
138
|
"numeric"
|
87
139
|
elsif klass == Date
|
@@ -100,11 +152,42 @@ module Sequel
|
|
100
152
|
"bytea"
|
101
153
|
end
|
102
154
|
end
|
155
|
+
|
156
|
+
# Do not auto parameterize string arrays by default.
|
157
|
+
def _bound_variable_type_for_string_array(r)
|
158
|
+
nil
|
159
|
+
end
|
160
|
+
|
161
|
+
# The minimium size of array to auto parameterize.
|
162
|
+
def pg_auto_parameterize_min_array_size
|
163
|
+
2
|
164
|
+
end
|
165
|
+
|
166
|
+
# Convert RHS of IN/NOT IN operator to PGArray with given type.
|
167
|
+
def _convert_array_to_pg_array_with_type(r, type)
|
168
|
+
Sequel.pg_array(r, type)
|
169
|
+
end
|
103
170
|
end
|
104
171
|
end
|
105
172
|
|
106
173
|
Database.register_extension(:pg_auto_parameterize_in_array) do |db|
|
107
174
|
db.extension(:pg_array, :pg_auto_parameterize)
|
108
175
|
db.extend_datasets(Postgres::AutoParameterizeInArray)
|
176
|
+
|
177
|
+
if db.typecast_value(:boolean, db.opts[:treat_string_list_as_text_array])
|
178
|
+
db.extend_datasets(Postgres::AutoParameterizeInArray::TreatStringListAsTextArray)
|
179
|
+
elsif db.typecast_value(:boolean, db.opts[:treat_string_list_as_untyped_array])
|
180
|
+
db.extend_datasets(Postgres::AutoParameterizeInArray::TreatStringListAsUntypedArray)
|
181
|
+
end
|
182
|
+
|
183
|
+
if min_array_size = db.opts[:pg_auto_parameterize_min_array_size]
|
184
|
+
min_array_size = db.typecast_value(:integer, min_array_size)
|
185
|
+
mod = Module.new do
|
186
|
+
define_method(:pg_auto_parameterize_min_array_size){min_array_size}
|
187
|
+
private :pg_auto_parameterize_min_array_size
|
188
|
+
end
|
189
|
+
Sequel.set_temp_name(mod){"Sequel::Postgres::AutoParameterizeInArray::_MinArraySize#{min_array_size}"}
|
190
|
+
db.extend_datasets(mod)
|
191
|
+
end
|
109
192
|
end
|
110
193
|
end
|
@@ -149,12 +149,12 @@ module Sequel
|
|
149
149
|
from(:pg_type).
|
150
150
|
where(:oid=>enum_labels.keys).
|
151
151
|
exclude(:typarray=>0).
|
152
|
-
select_map([:typname, Sequel.cast(:typarray, Integer).as(:v)])
|
152
|
+
select_map([:typname, Sequel.cast(:typarray, Integer).as(:v), Sequel.cast(:oid, Integer).as(:sv)])
|
153
153
|
|
154
154
|
existing_oids = conversion_procs.keys
|
155
|
-
array_types.each do |name, oid|
|
155
|
+
array_types.each do |name, oid, scalar_oid|
|
156
156
|
next if existing_oids.include?(oid)
|
157
|
-
register_array_type(name, :oid=>oid)
|
157
|
+
register_array_type(name, :oid=>oid, :scalar_oid=>scalar_oid)
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|