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
|
@@ -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
|
|
|
@@ -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
|
|
@@ -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
|
|
@@ -53,7 +54,7 @@ module Sequel
|
|
|
53
54
|
|
|
54
55
|
# Set the bind arguments based on the hash and call super.
|
|
55
56
|
def call(bind_vars=OPTS, &block)
|
|
56
|
-
sql = prepared_sql
|
|
57
|
+
sql = prepared_sql.freeze
|
|
57
58
|
prepared_args.freeze
|
|
58
59
|
ps = bind(bind_vars)
|
|
59
60
|
ps.clone(:bind_arguments=>ps.map_to_prepared_args(ps.opts[:bind_vars]), :sql=>sql, :prepared_sql=>sql).run(&block)
|
|
@@ -90,8 +91,14 @@ module Sequel
|
|
|
90
91
|
@opts[:log_sql]
|
|
91
92
|
end
|
|
92
93
|
|
|
93
|
-
# The type of
|
|
94
|
-
#
|
|
94
|
+
# The type of SQL to generate for the prepared statement. Generally
|
|
95
|
+
# the same as #prepared_type, but can be different.
|
|
96
|
+
def prepared_sql_type
|
|
97
|
+
@opts[:prepared_sql_type] || prepared_type
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# The type of prepared statement, which controls how the prepared statement
|
|
101
|
+
# handles results from the database.
|
|
95
102
|
def prepared_type
|
|
96
103
|
@opts[:prepared_type]
|
|
97
104
|
end
|
|
@@ -140,7 +147,7 @@ module Sequel
|
|
|
140
147
|
# Returns the SQL for the prepared statement, depending on
|
|
141
148
|
# the type of the statement and the prepared_modify_values.
|
|
142
149
|
def prepared_sql
|
|
143
|
-
case
|
|
150
|
+
case prepared_sql_type
|
|
144
151
|
when :select, :all, :each
|
|
145
152
|
# Most common scenario, so listed first.
|
|
146
153
|
select_sql
|
|
@@ -181,34 +188,30 @@ module Sequel
|
|
|
181
188
|
|
|
182
189
|
# Run the method based on the type of prepared statement.
|
|
183
190
|
def run(&block)
|
|
184
|
-
case prepared_type
|
|
191
|
+
case type = prepared_type
|
|
185
192
|
when :select, :all
|
|
186
|
-
|
|
193
|
+
with_sql_all(prepared_sql, &block)
|
|
187
194
|
when :each
|
|
188
|
-
|
|
189
|
-
when :insert_select
|
|
190
|
-
|
|
191
|
-
when :first
|
|
192
|
-
first
|
|
195
|
+
with_sql_each(prepared_sql, &block)
|
|
196
|
+
when :insert_select, :first
|
|
197
|
+
with_sql_first(prepared_sql)
|
|
193
198
|
when :insert, :update, :delete
|
|
194
199
|
if opts[:returning] && supports_returning?(prepared_type)
|
|
195
200
|
returning_fetch_rows(prepared_sql)
|
|
196
|
-
elsif
|
|
197
|
-
|
|
201
|
+
elsif type == :delete
|
|
202
|
+
with_sql_delete(prepared_sql)
|
|
198
203
|
else
|
|
199
|
-
public_send(
|
|
204
|
+
force_prepared_sql.public_send(type, *prepared_modify_values)
|
|
200
205
|
end
|
|
201
|
-
when :insert_pk
|
|
202
|
-
|
|
206
|
+
when :insert_pk, :single_value
|
|
207
|
+
with_sql_single_value(prepared_sql)
|
|
203
208
|
when Array
|
|
204
209
|
# :nocov:
|
|
205
|
-
case
|
|
210
|
+
case type[0]
|
|
206
211
|
# :nocov:
|
|
207
212
|
when :map, :as_hash, :to_hash, :to_hash_groups
|
|
208
|
-
public_send(*
|
|
213
|
+
force_prepared_sql.public_send(*type, &block)
|
|
209
214
|
end
|
|
210
|
-
when :single_value
|
|
211
|
-
single_value
|
|
212
215
|
else
|
|
213
216
|
raise Error, "unsupported prepared statement type used: #{prepared_type.inspect}"
|
|
214
217
|
end
|
|
@@ -216,6 +219,16 @@ module Sequel
|
|
|
216
219
|
|
|
217
220
|
private
|
|
218
221
|
|
|
222
|
+
# If the prepared_sql_type does not match the prepared statement, return a clone that
|
|
223
|
+
# with the prepared SQL, to ensure the prepared_sql_type is respected.
|
|
224
|
+
def force_prepared_sql
|
|
225
|
+
if prepared_sql_type != prepared_type
|
|
226
|
+
with_sql(prepared_sql.freeze)
|
|
227
|
+
else
|
|
228
|
+
self
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
219
232
|
# Returns the value of the prepared_args hash for the given key.
|
|
220
233
|
def prepared_arg(k)
|
|
221
234
|
@opts[:bind_vars][k]
|
|
@@ -274,7 +287,7 @@ module Sequel
|
|
|
274
287
|
|
|
275
288
|
def run(&block)
|
|
276
289
|
if @opts[:prepared_sql_frags]
|
|
277
|
-
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
|
|
278
291
|
clone(:prepared_sql_frags=>nil, :sql=>sql, :prepared_sql=>sql).run(&block)
|
|
279
292
|
else
|
|
280
293
|
super
|
|
@@ -293,11 +306,12 @@ module Sequel
|
|
|
293
306
|
prepared_sql, frags = Sequel::Dataset::PlaceholderLiteralizer::Recorder.new.send(:prepared_sql_and_frags, self, prepared_args) do |pl, ds|
|
|
294
307
|
ds = ds.clone(:recorder=>pl)
|
|
295
308
|
|
|
296
|
-
|
|
309
|
+
sql_type = prepared_sql_type || type
|
|
310
|
+
case sql_type
|
|
297
311
|
when :first, :single_value
|
|
298
312
|
ds.limit(1)
|
|
299
313
|
when :update, :insert, :insert_select, :delete
|
|
300
|
-
ds.with_sql(:"#{
|
|
314
|
+
ds.with_sql(:"#{sql_type}_sql", *values)
|
|
301
315
|
when :insert_pk
|
|
302
316
|
ds.with_sql(:insert_sql, *values)
|
|
303
317
|
else
|
|
@@ -306,6 +320,9 @@ module Sequel
|
|
|
306
320
|
end
|
|
307
321
|
|
|
308
322
|
prepared_args.freeze
|
|
323
|
+
frags.freeze
|
|
324
|
+
frags.each(&:freeze)
|
|
325
|
+
prepared_sql.freeze
|
|
309
326
|
clone(:prepared_sql_frags=>frags, :prepared_sql=>prepared_sql, :sql=>prepared_sql)
|
|
310
327
|
end
|
|
311
328
|
|
|
@@ -343,13 +360,23 @@ module Sequel
|
|
|
343
360
|
clone(:bind_vars=>bind_vars)
|
|
344
361
|
end
|
|
345
362
|
|
|
346
|
-
# For the given type
|
|
347
|
-
#
|
|
348
|
-
#
|
|
363
|
+
# For the given type, run the sql with the bind variables specified in the hash.
|
|
364
|
+
# +values+ is a hash passed to insert or update (if one of those types is used),
|
|
365
|
+
# which may contain placeholders.
|
|
366
|
+
#
|
|
367
|
+
# The following types are supported:
|
|
368
|
+
#
|
|
369
|
+
# * :select, :all, :each, :first, :single_value, :insert, :insert_select, :insert_pk, :update, :delete
|
|
370
|
+
# * Array where first element is :map, :as_hash, :to_hash, :to_hash_groups (remaining elements
|
|
371
|
+
# are passed to the related method)
|
|
349
372
|
#
|
|
350
373
|
# DB[:table].where(id: :$id).call(:first, id: 1)
|
|
351
374
|
# # SELECT * FROM table WHERE id = ? LIMIT 1 -- (1)
|
|
352
375
|
# # => {:id=>1}
|
|
376
|
+
#
|
|
377
|
+
# DB[:table].where(id: :$id).call(:update, {c: 1, id: 2}, col: :$c)
|
|
378
|
+
# # UPDATE table WHERE id = ? SET col = ? -- (2, 1)
|
|
379
|
+
# # => 1
|
|
353
380
|
def call(type, bind_variables=OPTS, *values, &block)
|
|
354
381
|
to_prepared_statement(type, values, :extend=>bound_variable_modules).call(bind_variables, &block)
|
|
355
382
|
end
|
|
@@ -370,6 +397,14 @@ module Sequel
|
|
|
370
397
|
# # => {:id=>1, :name=>'Blah'}
|
|
371
398
|
#
|
|
372
399
|
# DB.call(:select_by_name, name: 'Blah') # Same thing
|
|
400
|
+
#
|
|
401
|
+
# +values+ given are passed to +insert+ or +update+ if they are used:
|
|
402
|
+
#
|
|
403
|
+
# ps = DB[:table].where(id: :$i).prepare(:update, :update_name, name: :$n)
|
|
404
|
+
#
|
|
405
|
+
# ps.call(i: 1, n: 'Blah')
|
|
406
|
+
# # UPDATE table WHERE id = ? SET name = ? -- (1, 'Blah')
|
|
407
|
+
# # => 1
|
|
373
408
|
def prepare(type, name, *values)
|
|
374
409
|
ps = to_prepared_statement(type, values, :name=>name, :extend=>prepared_statement_modules, :no_delayed_evaluations=>true)
|
|
375
410
|
|
|
@@ -377,7 +412,7 @@ module Sequel
|
|
|
377
412
|
ps = ps.with_extend(EmulatePreparedStatementMethods)
|
|
378
413
|
ps.send(:emulated_prepared_statement, type, name, values)
|
|
379
414
|
else
|
|
380
|
-
sql = ps.prepared_sql
|
|
415
|
+
sql = ps.prepared_sql.freeze
|
|
381
416
|
ps.prepared_args.freeze
|
|
382
417
|
ps.clone(:prepared_sql=>sql, :sql=>sql)
|
|
383
418
|
end
|
|
@@ -386,6 +421,19 @@ module Sequel
|
|
|
386
421
|
ps
|
|
387
422
|
end
|
|
388
423
|
|
|
424
|
+
# Set the type of SQL to use for prepared statements based on this
|
|
425
|
+
# dataset. Prepared statements default to using the same SQL type
|
|
426
|
+
# as the type that is passed to #prepare/#call, but there are cases
|
|
427
|
+
# where it is helpful to use a different SQL type.
|
|
428
|
+
#
|
|
429
|
+
# Available types are: :select, :first, :single_value, :update,
|
|
430
|
+
# :delete, :insert, :insert_select, :insert_pk
|
|
431
|
+
#
|
|
432
|
+
# Other types are treated as :select.
|
|
433
|
+
def prepare_sql_type(type)
|
|
434
|
+
clone(:prepared_sql_type => type)
|
|
435
|
+
end
|
|
436
|
+
|
|
389
437
|
protected
|
|
390
438
|
|
|
391
439
|
# Return a cloned copy of the current dataset extended with
|
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)
|
|
@@ -231,8 +231,7 @@ module Sequel
|
|
|
231
231
|
#
|
|
232
232
|
# DB[:table].for_update # SELECT * FROM table FOR UPDATE
|
|
233
233
|
def for_update
|
|
234
|
-
|
|
235
|
-
cached_dataset(:_for_update_ds){lock_style(:update)}
|
|
234
|
+
cached_lock_style_dataset(:_for_update_ds, :update)
|
|
236
235
|
end
|
|
237
236
|
|
|
238
237
|
# Returns a copy of the dataset with the source changed. If no
|
|
@@ -1238,9 +1237,9 @@ module Sequel
|
|
|
1238
1237
|
# Note that like Object#extend, when multiple modules are provided
|
|
1239
1238
|
# as arguments the subclass includes the modules in reverse order.
|
|
1240
1239
|
def with_extend(*mods, &block)
|
|
1241
|
-
c = Class.new(self.class)
|
|
1240
|
+
c = Sequel.set_temp_name(Class.new(self.class)){"Sequel::Dataset::_Subclass"}
|
|
1242
1241
|
c.include(*mods) unless mods.empty?
|
|
1243
|
-
c.include(DatasetModule.new(&block)) if block
|
|
1242
|
+
c.include(Sequel.set_temp_name(DatasetModule.new(&block)){"Sequel::Dataset::_DatasetModule(#{block.source_location[0,2].join(':')})"}) if block
|
|
1244
1243
|
o = c.freeze.allocate
|
|
1245
1244
|
o.instance_variable_set(:@db, @db)
|
|
1246
1245
|
o.instance_variable_set(:@opts, @opts)
|
|
@@ -1302,7 +1301,7 @@ module Sequel
|
|
|
1302
1301
|
# * truncate (if a TRUNCATE statement, with no arguments)
|
|
1303
1302
|
def with_sql(sql, *args)
|
|
1304
1303
|
if sql.is_a?(Symbol)
|
|
1305
|
-
sql = public_send(sql, *args)
|
|
1304
|
+
sql = public_send(sql, *args).freeze
|
|
1306
1305
|
else
|
|
1307
1306
|
sql = SQL::PlaceholderLiteralString.new(sql, args) unless args.empty?
|
|
1308
1307
|
end
|
|
@@ -1359,9 +1358,13 @@ module Sequel
|
|
|
1359
1358
|
unless TRUE_FREEZE
|
|
1360
1359
|
# Load the extensions into the receiver, without checking if the receiver is frozen.
|
|
1361
1360
|
def _extension!(exts)
|
|
1362
|
-
Sequel.extension(*exts)
|
|
1363
1361
|
exts.each do |ext|
|
|
1364
|
-
|
|
1362
|
+
unless pr = Sequel.synchronize{EXTENSIONS[ext]}
|
|
1363
|
+
Sequel.extension(ext)
|
|
1364
|
+
pr = Sequel.synchronize{EXTENSIONS[ext]}
|
|
1365
|
+
end
|
|
1366
|
+
|
|
1367
|
+
if pr
|
|
1365
1368
|
pr.call(self)
|
|
1366
1369
|
else
|
|
1367
1370
|
raise(Error, "Extension #{ext} does not have specific support handling individual datasets (try: Sequel.extension #{ext.inspect})")
|
|
@@ -1458,11 +1461,23 @@ module Sequel
|
|
|
1458
1461
|
end
|
|
1459
1462
|
end
|
|
1460
1463
|
|
|
1464
|
+
# Internals of for_update and adapter-specific lock methods.
|
|
1465
|
+
# Returns receiver if it already uses this lock style, and a cached
|
|
1466
|
+
# dataset using the given key otherwise. The key could be derived from
|
|
1467
|
+
# the style, but doing so would require allocation, so pass it in as
|
|
1468
|
+
# an argument.
|
|
1469
|
+
def cached_lock_style_dataset(key, style)
|
|
1470
|
+
opts[:lock] == style ? self : cached_dataset(key){lock_style(style)}
|
|
1471
|
+
end
|
|
1472
|
+
|
|
1461
1473
|
# The default :qualify option to use for join tables if one is not specified.
|
|
1462
1474
|
def default_join_table_qualification
|
|
1463
1475
|
:symbol
|
|
1464
1476
|
end
|
|
1465
|
-
|
|
1477
|
+
|
|
1478
|
+
PAREN_WRAPPER = ["(".freeze, ")".freeze].freeze
|
|
1479
|
+
private_constant :PAREN_WRAPPER
|
|
1480
|
+
|
|
1466
1481
|
# SQL expression object based on the expr type. See +where+.
|
|
1467
1482
|
def filter_expr(expr = nil, &block)
|
|
1468
1483
|
expr = nil if expr == EMPTY_ARRAY
|
|
@@ -1483,8 +1498,8 @@ module Sequel
|
|
|
1483
1498
|
raise Error, "Invalid filter expression: #{expr.inspect}"
|
|
1484
1499
|
end
|
|
1485
1500
|
when LiteralString
|
|
1486
|
-
|
|
1487
|
-
when Numeric, SQL::NumericExpression, SQL::StringExpression, Proc, String
|
|
1501
|
+
SQL::PlaceholderLiteralString.new(PAREN_WRAPPER, [expr])
|
|
1502
|
+
when Numeric, SQL::NumericExpression, SQL::StringExpression, Proc, String, Set
|
|
1488
1503
|
raise Error, "Invalid filter expression: #{expr.inspect}"
|
|
1489
1504
|
when TrueClass, FalseClass
|
|
1490
1505
|
if supports_where_true?
|
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
|
|
@@ -85,6 +85,8 @@ module Sequel
|
|
|
85
85
|
literal_date_append(sql, v)
|
|
86
86
|
when Dataset
|
|
87
87
|
literal_dataset_append(sql, v)
|
|
88
|
+
when Set
|
|
89
|
+
literal_set_append(sql, v)
|
|
88
90
|
else
|
|
89
91
|
literal_other_append(sql, v)
|
|
90
92
|
end
|
|
@@ -375,9 +377,9 @@ module Sequel
|
|
|
375
377
|
cols = args[0]
|
|
376
378
|
vals = args[1]
|
|
377
379
|
col_array = true if cols.is_a?(Array)
|
|
378
|
-
if vals.is_a?(Array)
|
|
380
|
+
if vals.is_a?(Array) || vals.is_a?(Set)
|
|
379
381
|
val_array = true
|
|
380
|
-
empty_val_array = vals
|
|
382
|
+
empty_val_array = vals.empty?
|
|
381
383
|
end
|
|
382
384
|
if empty_val_array
|
|
383
385
|
literal_append(sql, empty_array_value(op, cols))
|
|
@@ -560,6 +562,7 @@ module Sequel
|
|
|
560
562
|
end
|
|
561
563
|
|
|
562
564
|
if window = opts[:over]
|
|
565
|
+
sql << ' IGNORE NULLS' if window.opts[:ignore_nulls]
|
|
563
566
|
sql << ' OVER '
|
|
564
567
|
window_sql_append(sql, window.opts)
|
|
565
568
|
end
|
|
@@ -636,12 +639,11 @@ module Sequel
|
|
|
636
639
|
if args.empty?
|
|
637
640
|
sql << str
|
|
638
641
|
else
|
|
639
|
-
re = /:(#{args.keys.map
|
|
640
|
-
|
|
642
|
+
re = /:(#{Regexp.union(args.keys.map(&:to_s))})\b/
|
|
643
|
+
until str.empty?
|
|
641
644
|
previous, q, str = str.partition(re)
|
|
642
645
|
sql << previous
|
|
643
|
-
literal_append(sql, args[
|
|
644
|
-
break if str.empty?
|
|
646
|
+
literal_append(sql, args[$1.to_sym]) unless q.empty?
|
|
645
647
|
end
|
|
646
648
|
end
|
|
647
649
|
elsif str.is_a?(Array)
|
|
@@ -685,10 +687,10 @@ module Sequel
|
|
|
685
687
|
# being quoted, returns name as a string. If identifiers are being quoted
|
|
686
688
|
# quote the name with quoted_identifier.
|
|
687
689
|
def quote_identifier_append(sql, name)
|
|
690
|
+
name = name.value if name.is_a?(SQL::Identifier)
|
|
688
691
|
if name.is_a?(LiteralString)
|
|
689
692
|
sql << name
|
|
690
693
|
else
|
|
691
|
-
name = name.value if name.is_a?(SQL::Identifier)
|
|
692
694
|
name = input_identifier(name)
|
|
693
695
|
if quote_identifiers?
|
|
694
696
|
quoted_identifier_append(sql, name)
|
|
@@ -700,11 +702,14 @@ module Sequel
|
|
|
700
702
|
|
|
701
703
|
# Append literalization of identifier or unqualified identifier to SQL string.
|
|
702
704
|
def quote_schema_table_append(sql, table)
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
705
|
+
qualifiers = split_qualifiers(table)
|
|
706
|
+
table = qualifiers.pop
|
|
707
|
+
|
|
708
|
+
qualifiers.each do |q|
|
|
709
|
+
quote_identifier_append(sql, q)
|
|
706
710
|
sql << '.'
|
|
707
711
|
end
|
|
712
|
+
|
|
708
713
|
quote_identifier_append(sql, table)
|
|
709
714
|
end
|
|
710
715
|
|
|
@@ -1032,7 +1037,7 @@ module Sequel
|
|
|
1032
1037
|
if column_aliases
|
|
1033
1038
|
raise Error, "#{db.database_type} does not support derived column lists" unless supports_derived_column_lists?
|
|
1034
1039
|
sql << '('
|
|
1035
|
-
|
|
1040
|
+
derived_column_list_sql_append(sql, column_aliases)
|
|
1036
1041
|
sql << ')'
|
|
1037
1042
|
end
|
|
1038
1043
|
end
|
|
@@ -1165,6 +1170,11 @@ module Sequel
|
|
|
1165
1170
|
end
|
|
1166
1171
|
end
|
|
1167
1172
|
|
|
1173
|
+
# Append the column aliases to the SQL.
|
|
1174
|
+
def derived_column_list_sql_append(sql, column_aliases)
|
|
1175
|
+
identifier_list_append(sql, column_aliases)
|
|
1176
|
+
end
|
|
1177
|
+
|
|
1168
1178
|
# Disable caching of SQL for the current dataset
|
|
1169
1179
|
def disable_sql_caching!
|
|
1170
1180
|
cache_set(:_no_cache_sql, true)
|
|
@@ -1331,7 +1341,7 @@ module Sequel
|
|
|
1331
1341
|
# SQL fragment specifying a JOIN type, converts underscores to
|
|
1332
1342
|
# spaces and upcases.
|
|
1333
1343
|
def join_type_sql(join_type)
|
|
1334
|
-
"#{join_type.to_s.
|
|
1344
|
+
"#{join_type.to_s.tr('_', ' ').upcase} JOIN"
|
|
1335
1345
|
end
|
|
1336
1346
|
|
|
1337
1347
|
# Append USING clause for JOIN USING
|
|
@@ -1415,6 +1425,11 @@ module Sequel
|
|
|
1415
1425
|
v.to_s
|
|
1416
1426
|
end
|
|
1417
1427
|
|
|
1428
|
+
# Append string to SQL string.
|
|
1429
|
+
def literal_literal_string_append(sql, v)
|
|
1430
|
+
sql << v
|
|
1431
|
+
end
|
|
1432
|
+
|
|
1418
1433
|
# SQL fragment for nil
|
|
1419
1434
|
def literal_nil
|
|
1420
1435
|
"NULL"
|
|
@@ -1425,10 +1440,6 @@ module Sequel
|
|
|
1425
1440
|
# calls +sql_literal+ if object responds to it, otherwise raises an error.
|
|
1426
1441
|
# If a database specific type is allowed, this should be overriden in a subclass.
|
|
1427
1442
|
def literal_other_append(sql, v)
|
|
1428
|
-
# We can't be sure if v will always literalize to the same SQL, so
|
|
1429
|
-
# don't cache SQL for a dataset that uses this.
|
|
1430
|
-
disable_sql_caching!
|
|
1431
|
-
|
|
1432
1443
|
if v.respond_to?(:sql_literal_append)
|
|
1433
1444
|
v.sql_literal_append(self, sql)
|
|
1434
1445
|
elsif v.respond_to?(:sql_literal)
|
|
@@ -1436,6 +1447,18 @@ module Sequel
|
|
|
1436
1447
|
else
|
|
1437
1448
|
raise Error, "can't express #{v.inspect} as a SQL literal"
|
|
1438
1449
|
end
|
|
1450
|
+
|
|
1451
|
+
if !v.respond_to?(:sql_literal_allow_caching?) || !v.sql_literal_allow_caching?(self)
|
|
1452
|
+
# We can't be sure if v will always literalize to the same SQL, so
|
|
1453
|
+
# don't cache SQL for a dataset that uses this.
|
|
1454
|
+
disable_sql_caching!
|
|
1455
|
+
end
|
|
1456
|
+
end
|
|
1457
|
+
|
|
1458
|
+
# Append a literalization of the set to SQL string.
|
|
1459
|
+
# Treats as an expression as an SQL value list.
|
|
1460
|
+
def literal_set_append(sql, v)
|
|
1461
|
+
array_sql_append(sql, v)
|
|
1439
1462
|
end
|
|
1440
1463
|
|
|
1441
1464
|
# SQL fragment for Sequel::SQLTime, containing just the time part
|
|
@@ -357,7 +357,7 @@ module Sequel
|
|
|
357
357
|
define_singleton_method(:async_job_class){proxy_klass}
|
|
358
358
|
|
|
359
359
|
queue = @async_thread_queue = Queue.new
|
|
360
|
-
pool = @async_thread_pool = num_async_threads
|
|
360
|
+
pool = @async_thread_pool = Array.new(num_async_threads){JobProcessor.new(queue)}
|
|
361
361
|
ObjectSpace.define_finalizer(db, JobProcessor.create_finalizer(queue, pool))
|
|
362
362
|
|
|
363
363
|
extend_datasets(DatasetMethods)
|
|
@@ -60,9 +60,7 @@ module Sequel
|
|
|
60
60
|
def external_caller_for_log
|
|
61
61
|
ignore = caller_logging_ignore
|
|
62
62
|
c = caller.find do |line|
|
|
63
|
-
!(line.start_with?(SEQUEL_LIB_PATH) ||
|
|
64
|
-
line.start_with?(RUBY_STDLIB) ||
|
|
65
|
-
line.start_with?(INTERNAL) ||
|
|
63
|
+
!(line.start_with?(SEQUEL_LIB_PATH, RUBY_STDLIB, INTERNAL) ||
|
|
66
64
|
(ignore && line =~ ignore))
|
|
67
65
|
end
|
|
68
66
|
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
#
|
|
3
|
+
# The connection_checkout_event_callback extension modifies a database's
|
|
4
|
+
# connection pool to allow for a checkout event callback. This callback is
|
|
5
|
+
# called with the following arguments:
|
|
6
|
+
#
|
|
7
|
+
# :immediately_available :: Connection immediately available and returned
|
|
8
|
+
# :not_immediately_available :: Connection not immediately available
|
|
9
|
+
# :new_connection :: New connection created and returned
|
|
10
|
+
# Float :: Number of seconds waiting to acquire a connection
|
|
11
|
+
#
|
|
12
|
+
# This is a low-level extension that allows for building telemetry
|
|
13
|
+
# information. It doesn't implement any telemetry reporting itself. The
|
|
14
|
+
# main reason for recording this information is to use it to determine the
|
|
15
|
+
# appropriate size for the connection pool. Having too large a connection
|
|
16
|
+
# pool can waste resources, while having too small a connection pool can
|
|
17
|
+
# result in substantial time to check out a connection. In general, you
|
|
18
|
+
# want to use as small a pool as possible while keeping the time to
|
|
19
|
+
# checkout a connection low.
|
|
20
|
+
#
|
|
21
|
+
# To use the connection checkout event callback, you must first load the
|
|
22
|
+
# extension:
|
|
23
|
+
#
|
|
24
|
+
# DB.extension(:connection_checkout_event_callback)
|
|
25
|
+
#
|
|
26
|
+
# By default, an empty proc is used as the callback so that loading the
|
|
27
|
+
# support doesn't break anything. If you are using the extension, you
|
|
28
|
+
# should set the callback at some point during application startup:
|
|
29
|
+
#
|
|
30
|
+
# DB.pool.on_checkout_event = proc do |event|
|
|
31
|
+
# # ...
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# When using the sharded connection pool, the callback is also
|
|
35
|
+
# passed a second argument, the requested server shard (generally a
|
|
36
|
+
# symbol), allowing for collection of per-shard telemetry:
|
|
37
|
+
#
|
|
38
|
+
# DB.pool.on_checkout_event = proc do |event, server|
|
|
39
|
+
# # ...
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# Note that the callback may be called currently by multiple threads.
|
|
43
|
+
# You should use some form of concurrency control inside the callback,
|
|
44
|
+
# such as a mutex or queue.
|
|
45
|
+
#
|
|
46
|
+
# Below is a brief example of usage to determine the percentage of
|
|
47
|
+
# connection requests where a connection was immediately available:
|
|
48
|
+
#
|
|
49
|
+
# mutex = Mutex.new
|
|
50
|
+
# total = immediates = 0
|
|
51
|
+
#
|
|
52
|
+
# DB.pool.on_checkout_event = proc do |event|
|
|
53
|
+
# case event
|
|
54
|
+
# when :immediately_available
|
|
55
|
+
# mutex.synchronize do
|
|
56
|
+
# total += 1
|
|
57
|
+
# immediates += 1
|
|
58
|
+
# end
|
|
59
|
+
# when :not_immediately_available
|
|
60
|
+
# mutex.synchronize do
|
|
61
|
+
# total += 1
|
|
62
|
+
# end
|
|
63
|
+
# end
|
|
64
|
+
# end
|
|
65
|
+
#
|
|
66
|
+
# immediate_percentage = lambda do
|
|
67
|
+
# mutex.synchronize do
|
|
68
|
+
# 100.0 * immediates / total
|
|
69
|
+
# end
|
|
70
|
+
# end
|
|
71
|
+
#
|
|
72
|
+
# Note that this extension only works with the timed_queue
|
|
73
|
+
# and sharded_timed_queue connection pools (the default
|
|
74
|
+
# connection pools when using Ruby 3.2+).
|
|
75
|
+
#
|
|
76
|
+
# Related modules: Sequel::ConnectionCheckoutEventCallbacks::TimedQueue,
|
|
77
|
+
# Sequel::ConnectionCheckoutEventCallbacks::ShardedTimedQueue
|
|
78
|
+
|
|
79
|
+
#
|
|
80
|
+
module Sequel
|
|
81
|
+
module ConnectionCheckoutEventCallbacks
|
|
82
|
+
module TimedQueue
|
|
83
|
+
# The callback that is called with connection checkout events.
|
|
84
|
+
attr_accessor :on_checkout_event
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def available
|
|
89
|
+
conn = super
|
|
90
|
+
@on_checkout_event.call(conn ? :immediately_available : :not_immediately_available)
|
|
91
|
+
conn
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def try_make_new
|
|
95
|
+
conn = super
|
|
96
|
+
@on_checkout_event.call(:new_connection) if conn
|
|
97
|
+
conn
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def wait_until_available
|
|
101
|
+
timer = Sequel.start_timer
|
|
102
|
+
conn = super
|
|
103
|
+
@on_checkout_event.call(Sequel.elapsed_seconds_since(timer))
|
|
104
|
+
conn
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
module ShardedTimedQueue
|
|
109
|
+
# The callback that is called with connection checkout events.
|
|
110
|
+
attr_accessor :on_checkout_event
|
|
111
|
+
|
|
112
|
+
private
|
|
113
|
+
|
|
114
|
+
def available(queue, server)
|
|
115
|
+
conn = super
|
|
116
|
+
@on_checkout_event.call(conn ? :immediately_available : :not_immediately_available, server)
|
|
117
|
+
conn
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def try_make_new(server)
|
|
121
|
+
conn = super
|
|
122
|
+
@on_checkout_event.call(:new_connection, server) if conn
|
|
123
|
+
conn
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def wait_until_available(queue, server)
|
|
127
|
+
timer = Sequel.start_timer
|
|
128
|
+
conn = super
|
|
129
|
+
@on_checkout_event.call(Sequel.elapsed_seconds_since(timer), server)
|
|
130
|
+
conn
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
default_callback = proc{}
|
|
136
|
+
|
|
137
|
+
Database.register_extension(:connection_checkout_event_callback) do |db|
|
|
138
|
+
pool = db.pool
|
|
139
|
+
|
|
140
|
+
case pool.pool_type
|
|
141
|
+
when :timed_queue
|
|
142
|
+
db.pool.extend(ConnectionCheckoutEventCallbacks::TimedQueue)
|
|
143
|
+
when :sharded_timed_queue
|
|
144
|
+
db.pool.extend(ConnectionCheckoutEventCallbacks::ShardedTimedQueue)
|
|
145
|
+
else
|
|
146
|
+
raise Error, "the connection_checkout_event_callback extension is only supported when using a timed_queue connection pool"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
pool.on_checkout_event ||= default_callback
|
|
150
|
+
end
|
|
151
|
+
end
|