sequel 5.83.0 → 5.106.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/ado/access.rb +2 -2
- data/lib/sequel/adapters/ado.rb +2 -2
- data/lib/sequel/adapters/amalgalite.rb +16 -1
- data/lib/sequel/adapters/ibmdb.rb +2 -1
- data/lib/sequel/adapters/jdbc/db2.rb +2 -2
- data/lib/sequel/adapters/jdbc/derby.rb +4 -2
- data/lib/sequel/adapters/jdbc/h2.rb +4 -4
- 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 +3 -3
- data/lib/sequel/adapters/jdbc/oracle.rb +6 -6
- 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 +3 -3
- data/lib/sequel/adapters/jdbc/sqlserver.rb +3 -3
- data/lib/sequel/adapters/jdbc.rb +29 -15
- data/lib/sequel/adapters/mysql.rb +1 -1
- data/lib/sequel/adapters/mysql2.rb +10 -3
- data/lib/sequel/adapters/odbc.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +16 -0
- data/lib/sequel/adapters/postgres.rb +2 -1
- data/lib/sequel/adapters/shared/access.rb +1 -0
- data/lib/sequel/adapters/shared/db2.rb +8 -3
- data/lib/sequel/adapters/shared/mssql.rb +9 -8
- data/lib/sequel/adapters/shared/mysql.rb +16 -11
- data/lib/sequel/adapters/shared/oracle.rb +1 -0
- data/lib/sequel/adapters/shared/postgres.rb +438 -47
- data/lib/sequel/adapters/shared/sqlite.rb +9 -7
- data/lib/sequel/adapters/sqlite.rb +20 -2
- data/lib/sequel/adapters/tinytds.rb +2 -2
- data/lib/sequel/adapters/trilogy.rb +2 -3
- data/lib/sequel/ast_transformer.rb +2 -0
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +42 -11
- data/lib/sequel/connection_pool/timed_queue.rb +33 -10
- data/lib/sequel/connection_pool.rb +8 -2
- data/lib/sequel/core.rb +31 -2
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/dataset_defaults.rb +3 -3
- data/lib/sequel/database/misc.rb +29 -11
- data/lib/sequel/database/query.rb +12 -12
- data/lib/sequel/database/schema_generator.rb +117 -16
- data/lib/sequel/database/schema_methods.rb +85 -30
- data/lib/sequel/dataset/actions.rb +83 -11
- data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +1 -1
- data/lib/sequel/dataset/placeholder_literalizer.rb +3 -0
- data/lib/sequel/dataset/prepared_statements.rb +76 -28
- data/lib/sequel/dataset/query.rb +26 -11
- data/lib/sequel/dataset/sql.rb +40 -17
- data/lib/sequel/extensions/async_thread_pool.rb +1 -1
- data/lib/sequel/extensions/caller_logging.rb +1 -3
- data/lib/sequel/extensions/connection_checkout_event_callback.rb +151 -0
- data/lib/sequel/extensions/connection_expiration.rb +44 -5
- data/lib/sequel/extensions/connection_validator.rb +15 -10
- data/lib/sequel/extensions/constraint_validations.rb +3 -3
- data/lib/sequel/extensions/dataset_run.rb +41 -0
- data/lib/sequel/extensions/date_arithmetic.rb +6 -6
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +7 -0
- data/lib/sequel/extensions/eval_inspect.rb +3 -1
- data/lib/sequel/extensions/inflector.rb +2 -2
- data/lib/sequel/extensions/lit_require_frozen.rb +131 -0
- data/lib/sequel/extensions/looser_typecasting.rb +5 -12
- data/lib/sequel/extensions/migration.rb +38 -21
- data/lib/sequel/extensions/null_dataset.rb +2 -2
- data/lib/sequel/extensions/pg_array_ops.rb +41 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +10 -3
- data/lib/sequel/extensions/pg_auto_parameterize_duplicate_query_detection.rb +191 -0
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +94 -10
- data/lib/sequel/extensions/pg_enum.rb +4 -4
- data/lib/sequel/extensions/pg_hstore.rb +1 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +10 -5
- data/lib/sequel/extensions/pg_json_ops.rb +674 -18
- data/lib/sequel/extensions/pg_multirange.rb +1 -1
- data/lib/sequel/extensions/pg_range.rb +14 -2
- data/lib/sequel/extensions/pg_row.rb +5 -3
- data/lib/sequel/extensions/pg_schema_caching.rb +90 -0
- data/lib/sequel/extensions/provenance.rb +1 -3
- 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 +17 -5
- data/lib/sequel/extensions/set_literalizer.rb +20 -39
- data/lib/sequel/extensions/split_array_nil.rb +12 -2
- data/lib/sequel/extensions/sqlite_json_ops.rb +1 -1
- data/lib/sequel/extensions/string_agg.rb +2 -2
- data/lib/sequel/extensions/to_dot.rb +5 -0
- data/lib/sequel/extensions/virtual_row_method_block.rb +1 -0
- data/lib/sequel/model/associations.rb +215 -15
- data/lib/sequel/model/base.rb +198 -35
- data/lib/sequel/model/plugins.rb +12 -1
- data/lib/sequel/model.rb +1 -0
- data/lib/sequel/plugins/accessed_columns.rb +4 -0
- data/lib/sequel/plugins/active_model.rb +5 -6
- data/lib/sequel/plugins/association_pks.rb +2 -0
- data/lib/sequel/plugins/auto_validations.rb +2 -0
- data/lib/sequel/plugins/class_table_inheritance_constraint_validations.rb +82 -0
- data/lib/sequel/plugins/columns_updated.rb +4 -0
- data/lib/sequel/plugins/composition.rb +3 -1
- data/lib/sequel/plugins/constraint_validations.rb +15 -10
- data/lib/sequel/plugins/dataset_associations.rb +20 -1
- data/lib/sequel/plugins/deprecated_associations.rb +151 -0
- data/lib/sequel/plugins/detect_unnecessary_association_options.rb +164 -0
- data/lib/sequel/plugins/dirty.rb +9 -2
- data/lib/sequel/plugins/enum.rb +1 -1
- data/lib/sequel/plugins/forbid_lazy_load.rb +15 -1
- data/lib/sequel/plugins/insert_conflict.rb +4 -0
- data/lib/sequel/plugins/insert_returning_select.rb +10 -1
- data/lib/sequel/plugins/inspect_pk.rb +44 -0
- data/lib/sequel/plugins/instance_filters.rb +8 -1
- data/lib/sequel/plugins/instance_hooks.rb +4 -0
- data/lib/sequel/plugins/inverted_subsets.rb +1 -0
- data/lib/sequel/plugins/json_serializer.rb +6 -10
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +21 -0
- data/lib/sequel/plugins/modification_detection.rb +2 -0
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +10 -5
- data/lib/sequel/plugins/paged_operations.rb +5 -2
- data/lib/sequel/plugins/pg_array_associations.rb +2 -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/pg_xmin_optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +6 -6
- data/lib/sequel/plugins/serialization.rb +23 -6
- data/lib/sequel/plugins/serialization_modification_detection.rb +4 -0
- data/lib/sequel/plugins/single_statement_dataset_destroy.rb +49 -0
- data/lib/sequel/plugins/split_values.rb +12 -0
- data/lib/sequel/plugins/sql_comments.rb +7 -2
- data/lib/sequel/plugins/static_cache.rb +13 -0
- 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 +278 -0
- data/lib/sequel/plugins/table_select.rb +7 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +4 -0
- data/lib/sequel/plugins/unused_associations.rb +11 -3
- data/lib/sequel/plugins/update_primary_key.rb +4 -0
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/plugins/validation_contexts.rb +4 -0
- data/lib/sequel/sql.rb +27 -12
- data/lib/sequel/version.rb +1 -1
- metadata +17 -240
- data/CHANGELOG +0 -1393
- 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 -104
- 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 -439
- 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.81.0.txt +0 -31
- data/doc/release_notes/5.82.0.txt +0 -61
- data/doc/release_notes/5.83.0.txt +0 -56
- 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 -204
- 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
|
@@ -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}
|
|
@@ -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
|
|
@@ -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)
|
|
@@ -349,7 +349,7 @@ module Sequel
|
|
|
349
349
|
ps
|
|
350
350
|
end
|
|
351
351
|
|
|
352
|
-
# Support creating STRICT AND/OR WITHOUT ROWID tables via :strict and :without_rowid options
|
|
352
|
+
# Support creating STRICT AND/OR WITHOUT ROWID tables via :strict and :without_rowid options, and VIRTUAL tables with :using option.
|
|
353
353
|
def create_table_sql(name, generator, options)
|
|
354
354
|
if options[:strict] && options[:without_rowid]
|
|
355
355
|
"#{super} STRICT, WITHOUT ROWID"
|
|
@@ -357,6 +357,8 @@ module Sequel
|
|
|
357
357
|
"#{super} STRICT"
|
|
358
358
|
elsif options[:without_rowid]
|
|
359
359
|
"#{super} WITHOUT ROWID"
|
|
360
|
+
elsif options[:using]
|
|
361
|
+
"CREATE VIRTUAL TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{create_table_table_name_sql(name, options)} USING #{options[:using]}"
|
|
360
362
|
else
|
|
361
363
|
super
|
|
362
364
|
end
|
|
@@ -405,7 +407,7 @@ module Sequel
|
|
|
405
407
|
def defined_columns_for(table)
|
|
406
408
|
cols = parse_pragma(table, OPTS)
|
|
407
409
|
cols.each do |c|
|
|
408
|
-
c[:default] = LiteralString.new(c[:default]) if c[:default]
|
|
410
|
+
c[:default] = LiteralString.new(c[:default]).freeze if c[:default]
|
|
409
411
|
c[:type] = c[:db_type]
|
|
410
412
|
end
|
|
411
413
|
cols
|
|
@@ -682,7 +684,7 @@ module Sequel
|
|
|
682
684
|
# Load the PrettyTable class, needed for explain output
|
|
683
685
|
Sequel.extension(:_pretty_table) unless defined?(Sequel::PrettyTable)
|
|
684
686
|
|
|
685
|
-
ds = db.send(:metadata_dataset).clone(:sql=>"EXPLAIN #{select_sql}")
|
|
687
|
+
ds = db.send(:metadata_dataset).clone(:sql=>"EXPLAIN #{select_sql}".freeze)
|
|
686
688
|
rows = ds.all
|
|
687
689
|
Sequel::PrettyTable.string(rows, ds.columns)
|
|
688
690
|
end
|
|
@@ -89,8 +89,22 @@ module Sequel
|
|
|
89
89
|
|
|
90
90
|
# Mimic the file:// uri, by having 2 preceding slashes specify a relative
|
|
91
91
|
# path, and 3 preceding slashes specify an absolute path.
|
|
92
|
+
# Also support no preceding slashes to specify a relative path.
|
|
92
93
|
def self.uri_to_options(uri) # :nodoc:
|
|
93
|
-
|
|
94
|
+
database = if uri.host.nil?
|
|
95
|
+
case uri.path
|
|
96
|
+
when '/'
|
|
97
|
+
nil
|
|
98
|
+
when nil
|
|
99
|
+
uri.opaque
|
|
100
|
+
else
|
|
101
|
+
uri.path
|
|
102
|
+
end
|
|
103
|
+
else
|
|
104
|
+
"#{uri.host}#{uri.path}"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
{ :database => database }
|
|
94
108
|
end
|
|
95
109
|
|
|
96
110
|
private_class_method :uri_to_options
|
|
@@ -109,6 +123,8 @@ module Sequel
|
|
|
109
123
|
# :database :: database name (filename or ':memory:' or file: URI)
|
|
110
124
|
# :readonly :: open database in read-only mode; useful for reading
|
|
111
125
|
# static data that you do not want to modify
|
|
126
|
+
# :disable_dqs :: disable double quoted strings in DDL and DML statements
|
|
127
|
+
# (requires SQLite 3.29.0+ and sqlite3 gem version 1.4.3+).
|
|
112
128
|
# :timeout :: how long to wait for the database to be available if it
|
|
113
129
|
# is locked, given in milliseconds (default is 5000)
|
|
114
130
|
# :setup_regexp_function :: enable use of Regexp objects with SQL
|
|
@@ -128,6 +144,8 @@ module Sequel
|
|
|
128
144
|
opts[:database] = ':memory:' if blank_object?(opts[:database])
|
|
129
145
|
sqlite3_opts = {}
|
|
130
146
|
sqlite3_opts[:readonly] = typecast_value_boolean(opts[:readonly]) if opts.has_key?(:readonly)
|
|
147
|
+
# SEQUEL6: Make strict: true the default behavior
|
|
148
|
+
sqlite3_opts[:strict] = typecast_value_boolean(opts[:disable_dqs]) if opts.has_key?(:disable_dqs)
|
|
131
149
|
db = ::SQLite3::Database.new(opts[:database].to_s, sqlite3_opts)
|
|
132
150
|
db.busy_timeout(typecast_value_integer(opts.fetch(:timeout, 5000)))
|
|
133
151
|
|
|
@@ -370,7 +388,7 @@ module Sequel
|
|
|
370
388
|
# SQLite uses a : before the name of the argument for named
|
|
371
389
|
# arguments.
|
|
372
390
|
def prepared_arg(k)
|
|
373
|
-
LiteralString.new("#{prepared_arg_placeholder}#{k.to_s.gsub('.', '__')}")
|
|
391
|
+
LiteralString.new("#{prepared_arg_placeholder}#{k.to_s.gsub('.', '__')}".freeze)
|
|
374
392
|
end
|
|
375
393
|
end
|
|
376
394
|
|
|
@@ -14,7 +14,7 @@ module Sequel
|
|
|
14
14
|
opts = server_opts(server)
|
|
15
15
|
opts[:username] = opts[:user]
|
|
16
16
|
c = TinyTds::Client.new(opts)
|
|
17
|
-
c.query_options
|
|
17
|
+
c.query_options[:cache_rows] = false
|
|
18
18
|
|
|
19
19
|
# SEQUEL6: Default to ansi: true
|
|
20
20
|
if opts[:ansi]
|
|
@@ -205,7 +205,7 @@ module Sequel
|
|
|
205
205
|
private
|
|
206
206
|
|
|
207
207
|
def prepared_arg(k)
|
|
208
|
-
LiteralString.new("@#{k.to_s.gsub('.', '__')}")
|
|
208
|
+
LiteralString.new("@#{k.to_s.gsub('.', '__')}".freeze)
|
|
209
209
|
end
|
|
210
210
|
end
|
|
211
211
|
|
|
@@ -62,8 +62,7 @@ module Sequel
|
|
|
62
62
|
private
|
|
63
63
|
|
|
64
64
|
def database_specific_error_class(exception, opts)
|
|
65
|
-
|
|
66
|
-
when /1205 - Lock wait timeout exceeded; try restarting transaction\z/
|
|
65
|
+
if exception.error_code == 1205
|
|
67
66
|
DatabaseLockTimeout
|
|
68
67
|
else
|
|
69
68
|
super
|
|
@@ -84,7 +83,7 @@ module Sequel
|
|
|
84
83
|
|
|
85
84
|
# Convert tinyint(1) type to boolean if convert_tinyint_to_bool is true
|
|
86
85
|
def schema_column_type(db_type)
|
|
87
|
-
db_type
|
|
86
|
+
db_type.start_with?("tinyint(1)") ? :boolean : super
|
|
88
87
|
end
|
|
89
88
|
end
|
|
90
89
|
|
|
@@ -71,7 +71,7 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
71
71
|
while true
|
|
72
72
|
conn = nil
|
|
73
73
|
begin
|
|
74
|
-
break unless (conn = queue
|
|
74
|
+
break unless (conn = available(queue, server)) && !conns[conn]
|
|
75
75
|
conns[conn] = true
|
|
76
76
|
yield conn
|
|
77
77
|
ensure
|
|
@@ -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
|
-
|
|
98
|
+
nconns = 0
|
|
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
|
|
@@ -140,6 +142,12 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
140
142
|
end
|
|
141
143
|
end
|
|
142
144
|
|
|
145
|
+
# The number of threads waiting to check out a connection for the given
|
|
146
|
+
# server.
|
|
147
|
+
def num_waiting(server=:default)
|
|
148
|
+
@queues[pick_server(server)].num_waiting
|
|
149
|
+
end
|
|
150
|
+
|
|
143
151
|
# The total number of connections in the pool. Using a non-existant server will return nil.
|
|
144
152
|
def size(server=:default)
|
|
145
153
|
sync{@sizes[server]}
|
|
@@ -161,7 +169,7 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
161
169
|
|
|
162
170
|
queue = @queues[server]
|
|
163
171
|
|
|
164
|
-
while conn = queue
|
|
172
|
+
while conn = available(queue, server)
|
|
165
173
|
@sizes[server] -= 1
|
|
166
174
|
conns << conn
|
|
167
175
|
end
|
|
@@ -219,6 +227,12 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
219
227
|
conns.each{|conn| disconnect_connection(conn)}
|
|
220
228
|
end
|
|
221
229
|
|
|
230
|
+
# Only for use by extension that need to disconnect a connection inside acquire.
|
|
231
|
+
# Takes the connection and any arguments accepted by acquire.
|
|
232
|
+
def disconnect_acquired_connection(conn, _, server)
|
|
233
|
+
disconnect_pool_connection(conn, server)
|
|
234
|
+
end
|
|
235
|
+
|
|
222
236
|
# Decrement the current size of the pool for the server when disconnecting connections.
|
|
223
237
|
#
|
|
224
238
|
# Calling code should not have the mutex when calling this.
|
|
@@ -238,11 +252,15 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
238
252
|
# after disconnecting to potentially add new connections to the
|
|
239
253
|
# pool, so the threads that are currently waiting for connections
|
|
240
254
|
# do not timeout after the pool is no longer full.
|
|
241
|
-
|
|
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)
|
|
242
259
|
queue = sync{@queues[server]}
|
|
243
|
-
if queue.num_waiting > 0
|
|
260
|
+
if nconns > 0 && queue.num_waiting > 0
|
|
244
261
|
Thread.new do
|
|
245
|
-
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
|
|
246
264
|
queue.push(conn)
|
|
247
265
|
end
|
|
248
266
|
end
|
|
@@ -291,7 +309,7 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
291
309
|
ensure
|
|
292
310
|
if to_disconnect
|
|
293
311
|
to_disconnect.each{|conn| disconnect_pool_connection(conn, server)}
|
|
294
|
-
fill_queue(server)
|
|
312
|
+
fill_queue(server, to_disconnect.size)
|
|
295
313
|
end
|
|
296
314
|
end
|
|
297
315
|
end
|
|
@@ -305,7 +323,7 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
305
323
|
# Calling code should not have the mutex when calling this.
|
|
306
324
|
def acquire(thread, server)
|
|
307
325
|
queue = sync{@queues[server]}
|
|
308
|
-
if conn = queue
|
|
326
|
+
if conn = available(queue, server) || try_make_new(server) || wait_until_available(queue, server)
|
|
309
327
|
sync{@allocated[server][thread] = conn}
|
|
310
328
|
else
|
|
311
329
|
name = db.opts[:name]
|
|
@@ -313,6 +331,19 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
313
331
|
end
|
|
314
332
|
end
|
|
315
333
|
|
|
334
|
+
# Return the next connection in the pool if there is one available. Returns nil
|
|
335
|
+
# if no connection is currently available.
|
|
336
|
+
def available(queue, _server)
|
|
337
|
+
queue.pop(timeout: 0)
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# Return the next connection in the pool if there is one available. If not, wait
|
|
341
|
+
# until the timeout for a connection to become available. If there is still no
|
|
342
|
+
# available connection, return nil.
|
|
343
|
+
def wait_until_available(queue, _server)
|
|
344
|
+
queue.pop(timeout: @timeout)
|
|
345
|
+
end
|
|
346
|
+
|
|
316
347
|
# Returns the connection owned by the supplied thread for the given server,
|
|
317
348
|
# if any. The calling code should NOT already have the mutex before calling this.
|
|
318
349
|
def owned_connection(thread, server)
|
|
@@ -42,7 +42,7 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
42
42
|
while true
|
|
43
43
|
conn = nil
|
|
44
44
|
begin
|
|
45
|
-
break unless (conn =
|
|
45
|
+
break unless (conn = available) && !conns[conn]
|
|
46
46
|
conns[conn] = true
|
|
47
47
|
yield conn
|
|
48
48
|
ensure
|
|
@@ -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
|
-
|
|
62
|
+
nconns = 0
|
|
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
|
|
@@ -102,6 +104,11 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
102
104
|
end
|
|
103
105
|
end
|
|
104
106
|
|
|
107
|
+
# The number of threads waiting to check out a connection.
|
|
108
|
+
def num_waiting(_server=:default)
|
|
109
|
+
@queue.num_waiting
|
|
110
|
+
end
|
|
111
|
+
|
|
105
112
|
def pool_type
|
|
106
113
|
:timed_queue
|
|
107
114
|
end
|
|
@@ -151,10 +158,13 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
151
158
|
# after disconnecting to potentially add new connections to the
|
|
152
159
|
# pool, so the threads that are currently waiting for connections
|
|
153
160
|
# do not timeout after the pool is no longer full.
|
|
154
|
-
|
|
155
|
-
|
|
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
|
|
156
166
|
Thread.new do
|
|
157
|
-
while @queue.num_waiting > 0 && (conn = try_make_new)
|
|
167
|
+
while nconns > 0 && @queue.num_waiting > 0 && (conn = try_make_new)
|
|
158
168
|
@queue.push(conn)
|
|
159
169
|
end
|
|
160
170
|
end
|
|
@@ -202,7 +212,7 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
202
212
|
ensure
|
|
203
213
|
if to_disconnect
|
|
204
214
|
to_disconnect.each{|conn| disconnect_connection(conn)}
|
|
205
|
-
fill_queue
|
|
215
|
+
fill_queue(to_disconnect.size)
|
|
206
216
|
end
|
|
207
217
|
end
|
|
208
218
|
end
|
|
@@ -215,7 +225,7 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
215
225
|
#
|
|
216
226
|
# Calling code should not have the mutex when calling this.
|
|
217
227
|
def acquire(thread)
|
|
218
|
-
if conn =
|
|
228
|
+
if conn = available || try_make_new || wait_until_available
|
|
219
229
|
sync{@allocated[thread] = conn}
|
|
220
230
|
else
|
|
221
231
|
name = db.opts[:name]
|
|
@@ -223,6 +233,19 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
223
233
|
end
|
|
224
234
|
end
|
|
225
235
|
|
|
236
|
+
# Return the next connection in the pool if there is one available. Returns nil
|
|
237
|
+
# if no connection is currently available.
|
|
238
|
+
def available
|
|
239
|
+
@queue.pop(timeout: 0)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Return the next connection in the pool if there is one available. If not, wait
|
|
243
|
+
# until the timeout for a connection to become available. If there is still no
|
|
244
|
+
# available connection, return nil.
|
|
245
|
+
def wait_until_available
|
|
246
|
+
@queue.pop(timeout: @timeout)
|
|
247
|
+
end
|
|
248
|
+
|
|
226
249
|
# Returns the connection owned by the supplied thread,
|
|
227
250
|
# if any. The calling code should NOT already have the mutex before calling this.
|
|
228
251
|
def owned_connection(thread)
|
|
@@ -236,7 +259,7 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
|
|
|
236
259
|
def preconnect(concurrent = false)
|
|
237
260
|
if concurrent
|
|
238
261
|
if times = sync{@max_size > (size = @size[0]) ? @max_size - size : false}
|
|
239
|
-
|
|
262
|
+
Array.new(times){Thread.new{if conn = try_make_new; @queue.push(conn) end}}.map(&:value)
|
|
240
263
|
end
|
|
241
264
|
else
|
|
242
265
|
while conn = try_make_new
|
|
@@ -70,13 +70,13 @@ class Sequel::ConnectionPool
|
|
|
70
70
|
else
|
|
71
71
|
pc = if opts[:single_threaded]
|
|
72
72
|
opts[:servers] ? :sharded_single : :single
|
|
73
|
-
|
|
74
|
-
elsif RUBY_VERSION >= '3.4' # SEQUEL6 or maybe earlier switch to 3.2
|
|
73
|
+
elsif RUBY_VERSION >= '3.2'
|
|
75
74
|
opts[:servers] ? :sharded_timed_queue : :timed_queue
|
|
76
75
|
# :nocov:
|
|
77
76
|
else
|
|
78
77
|
opts[:servers] ? :sharded_threaded : :threaded
|
|
79
78
|
end
|
|
79
|
+
# :nocov:
|
|
80
80
|
|
|
81
81
|
connection_pool_class(:pool_class=>pc)
|
|
82
82
|
end
|
|
@@ -131,6 +131,12 @@ class Sequel::ConnectionPool
|
|
|
131
131
|
db.disconnect_connection(conn)
|
|
132
132
|
end
|
|
133
133
|
|
|
134
|
+
# Only for use by extension that need to disconnect a connection inside acquire.
|
|
135
|
+
# Takes the connection and any arguments accepted by acquire.
|
|
136
|
+
def disconnect_acquired_connection(conn, *)
|
|
137
|
+
disconnect_connection(conn)
|
|
138
|
+
end
|
|
139
|
+
|
|
134
140
|
# Whether the given exception is a disconnect exception.
|
|
135
141
|
def disconnect_error?(exception)
|
|
136
142
|
exception.is_a?(Sequel::DatabaseDisconnectError) || db.send(:disconnect_error?, exception, OPTS)
|
data/lib/sequel/core.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen-string-literal: true
|
|
2
2
|
|
|
3
|
-
%w'bigdecimal date thread time uri'.each{|f| require f}
|
|
3
|
+
%w'bigdecimal date set thread time uri'.each{|f| require f}
|
|
4
4
|
|
|
5
5
|
# Top level module for Sequel
|
|
6
6
|
#
|
|
@@ -164,6 +164,35 @@ module Sequel
|
|
|
164
164
|
JSON::ParserError
|
|
165
165
|
end
|
|
166
166
|
|
|
167
|
+
if RUBY_VERSION >= '3'
|
|
168
|
+
# Join the array or set.
|
|
169
|
+
def array_or_set_join(obj, arg)
|
|
170
|
+
obj.join(arg)
|
|
171
|
+
end
|
|
172
|
+
# :nocov:
|
|
173
|
+
else
|
|
174
|
+
def array_or_set_join(obj, arg)
|
|
175
|
+
obj = obj.to_a if obj.is_a?(Set)
|
|
176
|
+
obj.join(arg)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
# :nocov:
|
|
180
|
+
|
|
181
|
+
if RUBY_VERSION >= '3.3'
|
|
182
|
+
# Create a new module using the block, and set the temporary name
|
|
183
|
+
# on it using the given a containing module and name.
|
|
184
|
+
def set_temp_name(mod)
|
|
185
|
+
mod.set_temporary_name(yield)
|
|
186
|
+
mod
|
|
187
|
+
end
|
|
188
|
+
# :nocov:
|
|
189
|
+
else
|
|
190
|
+
def set_temp_name(mod)
|
|
191
|
+
mod
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
# :nocov:
|
|
195
|
+
|
|
167
196
|
# Convert given object to json and return the result.
|
|
168
197
|
# This can be overridden to use an alternative json implementation.
|
|
169
198
|
def object_to_json(obj, *args, &block)
|
|
@@ -388,7 +417,7 @@ module Sequel
|
|
|
388
417
|
when -1, 0
|
|
389
418
|
vr.instance_exec(&block)
|
|
390
419
|
else
|
|
391
|
-
|
|
420
|
+
yield(vr)
|
|
392
421
|
end
|
|
393
422
|
end
|
|
394
423
|
|
|
@@ -34,7 +34,7 @@ module Sequel
|
|
|
34
34
|
uri = URI.parse(conn_string)
|
|
35
35
|
scheme = uri.scheme
|
|
36
36
|
c = adapter_class(scheme)
|
|
37
|
-
opts = c.send(:
|
|
37
|
+
opts = c.send(:options_from_uri, uri).merge!(opts).merge!(:orig_opts=>opts.dup, :uri=>conn_string, :adapter=>scheme)
|
|
38
38
|
end
|
|
39
39
|
when Hash
|
|
40
40
|
opts = conn_string.merge(opts)
|
|
@@ -17,7 +17,7 @@ module Sequel
|
|
|
17
17
|
# as the dataset class.
|
|
18
18
|
def dataset_class=(c)
|
|
19
19
|
unless @dataset_modules.empty?
|
|
20
|
-
c = Class.new(c)
|
|
20
|
+
c = Sequel.set_temp_name(Class.new(c)){"Sequel::Dataset::_Subclass"}
|
|
21
21
|
@dataset_modules.each{|m| c.send(:include, m)}
|
|
22
22
|
end
|
|
23
23
|
@dataset_class = c
|
|
@@ -61,10 +61,10 @@ module Sequel
|
|
|
61
61
|
# # SELECT id, name FROM table WHERE active ORDER BY id
|
|
62
62
|
def extend_datasets(mod=nil, &block)
|
|
63
63
|
raise(Error, "must provide either mod or block, not both") if mod && block
|
|
64
|
-
mod = Dataset::DatasetModule.new(&block) if block
|
|
64
|
+
mod = Sequel.set_temp_name(Dataset::DatasetModule.new(&block)){"Sequel::Dataset::_DatasetModule(#{block.source_location[0,2].join(':')})"} if block
|
|
65
65
|
if @dataset_modules.empty?
|
|
66
66
|
@dataset_modules = [mod]
|
|
67
|
-
@dataset_class = Class.new(@dataset_class)
|
|
67
|
+
@dataset_class = Sequel.set_temp_name(Class.new(@dataset_class)){"Sequel::Dataset::_Subclass"}
|
|
68
68
|
else
|
|
69
69
|
@dataset_modules << mod
|
|
70
70
|
end
|
data/lib/sequel/database/misc.rb
CHANGED
|
@@ -26,18 +26,23 @@ module Sequel
|
|
|
26
26
|
:time=>Sequel::SQLTime, :boolean=>[TrueClass, FalseClass].freeze, :float=>Float, :decimal=>BigDecimal,
|
|
27
27
|
:blob=>Sequel::SQL::Blob}.freeze
|
|
28
28
|
|
|
29
|
+
# :nocov:
|
|
30
|
+
URI_PARSER = defined?(::URI::RFC2396_PARSER) ? ::URI::RFC2396_PARSER : ::URI::DEFAULT_PARSER
|
|
31
|
+
# :nocov:
|
|
32
|
+
private_constant :URI_PARSER
|
|
33
|
+
|
|
29
34
|
# Nested hook Proc; each new hook Proc just wraps the previous one.
|
|
30
35
|
@initialize_hook = proc{|db| }
|
|
31
36
|
|
|
32
37
|
# Register a hook that will be run when a new Database is instantiated. It is
|
|
33
38
|
# called with the new database handle.
|
|
34
|
-
def self.after_initialize
|
|
35
|
-
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)
|
|
36
41
|
Sequel.synchronize do
|
|
37
42
|
previous = @initialize_hook
|
|
38
43
|
@initialize_hook = proc do |db|
|
|
39
44
|
previous.call(db)
|
|
40
|
-
|
|
45
|
+
yield(db)
|
|
41
46
|
end
|
|
42
47
|
end
|
|
43
48
|
end
|
|
@@ -72,18 +77,23 @@ module Sequel
|
|
|
72
77
|
# Converts a uri to an options hash. These options are then passed
|
|
73
78
|
# to a newly created database object.
|
|
74
79
|
def self.uri_to_options(uri)
|
|
75
|
-
|
|
80
|
+
{
|
|
76
81
|
:user => uri.user,
|
|
77
82
|
:password => uri.password,
|
|
78
83
|
:port => uri.port,
|
|
79
84
|
:host => uri.hostname,
|
|
80
85
|
:database => (m = /\/(.*)/.match(uri.path)) && (m[1])
|
|
81
86
|
}
|
|
87
|
+
end
|
|
88
|
+
private_class_method :uri_to_options
|
|
89
|
+
|
|
90
|
+
def self.options_from_uri(uri)
|
|
91
|
+
uri_options = uri_to_options(uri)
|
|
82
92
|
uri.query.split('&').map{|s| s.split('=')}.each{|k,v| uri_options[k.to_sym] = v if k && !k.empty?} unless uri.query.to_s.strip.empty?
|
|
83
|
-
uri_options.to_a.each{|k,v| uri_options[k] =
|
|
93
|
+
uri_options.to_a.each{|k,v| uri_options[k] = URI_PARSER.unescape(v) if v.is_a?(String)}
|
|
84
94
|
uri_options
|
|
85
95
|
end
|
|
86
|
-
private_class_method :
|
|
96
|
+
private_class_method :options_from_uri
|
|
87
97
|
|
|
88
98
|
# The options hash for this database
|
|
89
99
|
attr_reader :opts
|
|
@@ -106,6 +116,10 @@ module Sequel
|
|
|
106
116
|
# :after_connect :: A callable object called after each new connection is made, with the
|
|
107
117
|
# connection object (and server argument if the callable accepts 2 arguments),
|
|
108
118
|
# useful for customizations that you want to apply to all connections.
|
|
119
|
+
# :compare_connections_by_identity :: Whether to use compare_by_identity on hashes that use
|
|
120
|
+
# connection objects as keys. Defaults to true. This should only
|
|
121
|
+
# be set to false to work around bugs in libraries or
|
|
122
|
+
# ruby implementations.
|
|
109
123
|
# :before_preconnect :: Callable that runs after extensions from :preconnect_extensions are loaded,
|
|
110
124
|
# but before any connections are created.
|
|
111
125
|
# :cache_schema :: Whether schema should be cached for this Database instance
|
|
@@ -155,7 +169,7 @@ module Sequel
|
|
|
155
169
|
@schemas = {}
|
|
156
170
|
@prepared_statements = {}
|
|
157
171
|
@transactions = {}
|
|
158
|
-
@transactions.compare_by_identity
|
|
172
|
+
@transactions.compare_by_identity if typecast_value_boolean(@opts.fetch(:compare_connections_by_identity, true))
|
|
159
173
|
@symbol_literal_cache = {}
|
|
160
174
|
|
|
161
175
|
@timezone = nil
|
|
@@ -236,9 +250,13 @@ module Sequel
|
|
|
236
250
|
# extension does not have specific support for Database objects, an Error will be raised.
|
|
237
251
|
# Returns self.
|
|
238
252
|
def extension(*exts)
|
|
239
|
-
Sequel.extension(*exts)
|
|
240
253
|
exts.each do |ext|
|
|
241
|
-
|
|
254
|
+
unless pr = Sequel.synchronize{EXTENSIONS[ext]}
|
|
255
|
+
Sequel.extension(ext)
|
|
256
|
+
pr = Sequel.synchronize{EXTENSIONS[ext]}
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
if pr
|
|
242
260
|
if Sequel.synchronize{@loaded_extensions.include?(ext) ? false : (@loaded_extensions << ext)}
|
|
243
261
|
pr.call(self)
|
|
244
262
|
end
|
|
@@ -266,7 +284,7 @@ module Sequel
|
|
|
266
284
|
keys = [:host, :database, :user]
|
|
267
285
|
opts = self.opts
|
|
268
286
|
if !keys.any?{|k| opts[k]} && opts[:uri]
|
|
269
|
-
opts = self.class.send(:
|
|
287
|
+
opts = self.class.send(:options_from_uri, URI.parse(opts[:uri]))
|
|
270
288
|
end
|
|
271
289
|
|
|
272
290
|
keys.each do |key|
|
|
@@ -617,7 +635,7 @@ module Sequel
|
|
|
617
635
|
# Typecast the value to a String
|
|
618
636
|
def typecast_value_string(value)
|
|
619
637
|
case value
|
|
620
|
-
when Hash, Array
|
|
638
|
+
when Hash, Array, Set
|
|
621
639
|
raise Sequel::InvalidValue, "invalid value for String: #{value.inspect}"
|
|
622
640
|
else
|
|
623
641
|
value.to_s
|