activerecord 8.0.0 → 8.1.4
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/CHANGELOG.md +1381 -241
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/association.rb +35 -17
- data/lib/active_record/associations/association_scope.rb +1 -1
- data/lib/active_record/associations/belongs_to_association.rb +20 -4
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +36 -8
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +9 -5
- data/lib/active_record/associations/collection_proxy.rb +26 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/foreign_association.rb +3 -1
- data/lib/active_record/associations/has_one_association.rb +1 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/associations/join_dependency.rb +5 -4
- data/lib/active_record/associations/preloader/association.rb +1 -1
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +1 -0
- data/lib/active_record/associations.rb +159 -21
- data/lib/active_record/attribute_methods/primary_key.rb +2 -1
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +19 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +10 -2
- data/lib/active_record/attribute_methods.rb +24 -17
- data/lib/active_record/attributes.rb +40 -26
- data/lib/active_record/autosave_association.rb +22 -12
- data/lib/active_record/base.rb +3 -4
- data/lib/active_record/callbacks.rb +1 -2
- data/lib/active_record/coders/column_serializer.rb +1 -1
- data/lib/active_record/coders/json.rb +16 -6
- data/lib/active_record/coders/yaml_column.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +19 -18
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +68 -12
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +474 -112
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +68 -41
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +36 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -24
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +7 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +31 -35
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +94 -28
- data/lib/active_record/connection_adapters/abstract/transaction.rb +25 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -64
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +133 -40
- data/lib/active_record/connection_adapters/column.rb +14 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +42 -5
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +40 -25
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +66 -15
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +9 -3
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +29 -33
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +46 -3
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +8 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -33
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +70 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +99 -54
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +40 -12
- data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +39 -23
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +15 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +7 -14
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +68 -37
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +8 -3
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +16 -2
- data/lib/active_record/connection_adapters.rb +1 -0
- data/lib/active_record/connection_handling.rb +15 -10
- data/lib/active_record/core.rb +44 -12
- data/lib/active_record/counter_cache.rb +36 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/database_configurations/database_config.rb +5 -1
- data/lib/active_record/database_configurations/hash_config.rb +66 -9
- data/lib/active_record/database_configurations/url_config.rb +15 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +19 -19
- data/lib/active_record/disable_joins_association_relation.rb +5 -1
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/encryptable_record.rb +5 -5
- data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
- data/lib/active_record/encryption/encrypted_fixtures.rb +12 -7
- data/lib/active_record/encryption/encryptor.rb +39 -25
- data/lib/active_record/encryption/scheme.rb +1 -1
- data/lib/active_record/enum.rb +37 -20
- data/lib/active_record/errors.rb +23 -7
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +76 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +2 -2
- data/lib/active_record/future_result.rb +5 -3
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +9 -4
- data/lib/active_record/insert_all.rb +14 -9
- data/lib/active_record/locking/optimistic.rb +7 -0
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +30 -22
- data/lib/active_record/message_pack.rb +13 -0
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +32 -6
- data/lib/active_record/migration/compatibility.rb +34 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +31 -21
- data/lib/active_record/model_schema.rb +38 -12
- data/lib/active_record/nested_attributes.rb +10 -6
- data/lib/active_record/persistence.rb +35 -3
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +7 -7
- data/lib/active_record/querying.rb +17 -5
- data/lib/active_record/railtie.rb +35 -6
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +24 -20
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +36 -1
- data/lib/active_record/relation/batches.rb +25 -11
- data/lib/active_record/relation/calculations.rb +62 -41
- data/lib/active_record/relation/delegation.rb +0 -1
- data/lib/active_record/relation/finder_methods.rb +76 -45
- data/lib/active_record/relation/merger.rb +4 -2
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +7 -7
- data/lib/active_record/relation/predicate_builder.rb +10 -8
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +106 -45
- data/lib/active_record/relation/spawn_methods.rb +6 -6
- data/lib/active_record/relation/where_clause.rb +10 -11
- data/lib/active_record/relation.rb +63 -31
- data/lib/active_record/result.rb +44 -21
- data/lib/active_record/runtime_registry.rb +42 -58
- data/lib/active_record/sanitization.rb +2 -0
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +41 -21
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +48 -19
- data/lib/active_record/statement_cache.rb +16 -12
- data/lib/active_record/store.rb +46 -19
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +5 -20
- data/lib/active_record/tasks/abstract_tasks.rb +83 -0
- data/lib/active_record/tasks/database_tasks.rb +44 -45
- data/lib/active_record/tasks/mysql_database_tasks.rb +4 -56
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -26
- data/lib/active_record/test_databases.rb +18 -4
- data/lib/active_record/test_fixtures.rb +40 -6
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +58 -32
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +13 -2
- data/lib/active_record/type/serialized.rb +16 -4
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +2 -1
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record.rb +72 -7
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/collectors/bind.rb +1 -1
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/node.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/predications.rb +1 -3
- data/lib/arel/select_manager.rb +13 -4
- data/lib/arel/update_manager.rb +5 -0
- data/lib/arel/visitors/dot.rb +2 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +7 -23
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +16 -15
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -163
|
@@ -5,6 +5,7 @@ require "active_record/connection_adapters/abstract/schema_dumper"
|
|
|
5
5
|
require "active_record/connection_adapters/abstract/schema_creation"
|
|
6
6
|
require "active_support/concurrency/null_lock"
|
|
7
7
|
require "active_support/concurrency/load_interlock_aware_monitor"
|
|
8
|
+
require "active_support/concurrency/thread_monitor"
|
|
8
9
|
require "arel/collectors/bind"
|
|
9
10
|
require "arel/collectors/composite"
|
|
10
11
|
require "arel/collectors/sql_string"
|
|
@@ -42,6 +43,8 @@ module ActiveRecord
|
|
|
42
43
|
|
|
43
44
|
attr_reader :pool
|
|
44
45
|
attr_reader :visitor, :owner, :logger, :lock
|
|
46
|
+
attr_reader :allow_preconnect # :nodoc:
|
|
47
|
+
attr_accessor :pinned # :nodoc:
|
|
45
48
|
alias :in_use? :owner
|
|
46
49
|
|
|
47
50
|
def pool=(value)
|
|
@@ -50,7 +53,11 @@ module ActiveRecord
|
|
|
50
53
|
@pool = value
|
|
51
54
|
end
|
|
52
55
|
|
|
53
|
-
|
|
56
|
+
def allow_preconnect=(value) # :nodoc:
|
|
57
|
+
@lock.synchronize do
|
|
58
|
+
@allow_preconnect = value
|
|
59
|
+
end
|
|
60
|
+
end
|
|
54
61
|
|
|
55
62
|
def self.type_cast_config_to_integer(config)
|
|
56
63
|
if config.is_a?(Integer)
|
|
@@ -119,7 +126,7 @@ module ActiveRecord
|
|
|
119
126
|
|
|
120
127
|
# Opens a database console session.
|
|
121
128
|
def self.dbconsole(config, options = {})
|
|
122
|
-
raise NotImplementedError
|
|
129
|
+
raise NotImplementedError.new("#{self} should define `dbconsole` that accepts a db config and options to implement connecting to the db console")
|
|
123
130
|
end
|
|
124
131
|
|
|
125
132
|
def initialize(config_or_deprecated_connection, deprecated_logger = nil, deprecated_connection_options = nil, deprecated_config = nil) # :nodoc:
|
|
@@ -127,6 +134,7 @@ module ActiveRecord
|
|
|
127
134
|
|
|
128
135
|
@raw_connection = nil
|
|
129
136
|
@unconfigured_connection = nil
|
|
137
|
+
@connected_since = nil
|
|
130
138
|
|
|
131
139
|
if config_or_deprecated_connection.is_a?(Hash)
|
|
132
140
|
@config = config_or_deprecated_connection.symbolize_keys
|
|
@@ -139,6 +147,7 @@ module ActiveRecord
|
|
|
139
147
|
# Soft-deprecated for now; we'll probably warn in future.
|
|
140
148
|
|
|
141
149
|
@unconfigured_connection = config_or_deprecated_connection
|
|
150
|
+
@connected_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
142
151
|
@logger = deprecated_logger || ActiveRecord::Base.logger
|
|
143
152
|
if deprecated_config
|
|
144
153
|
@config = (deprecated_config || {}).symbolize_keys
|
|
@@ -150,9 +159,10 @@ module ActiveRecord
|
|
|
150
159
|
end
|
|
151
160
|
|
|
152
161
|
@owner = nil
|
|
153
|
-
@
|
|
162
|
+
@pinned = false
|
|
154
163
|
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
|
155
164
|
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
165
|
+
@allow_preconnect = false
|
|
156
166
|
@visitor = arel_visitor
|
|
157
167
|
@statements = build_statement_pool
|
|
158
168
|
self.lock_thread = nil
|
|
@@ -168,7 +178,10 @@ module ActiveRecord
|
|
|
168
178
|
@default_timezone = self.class.validate_default_timezone(@config[:default_timezone])
|
|
169
179
|
|
|
170
180
|
@raw_connection_dirty = false
|
|
181
|
+
@last_activity = nil
|
|
171
182
|
@verified = false
|
|
183
|
+
|
|
184
|
+
@pool_jitter = rand * max_jitter
|
|
172
185
|
end
|
|
173
186
|
|
|
174
187
|
def inspect # :nodoc:
|
|
@@ -182,31 +195,23 @@ module ActiveRecord
|
|
|
182
195
|
@lock =
|
|
183
196
|
case lock_thread
|
|
184
197
|
when Thread
|
|
185
|
-
ActiveSupport::Concurrency::
|
|
198
|
+
ActiveSupport::Concurrency::ThreadMonitor.new
|
|
186
199
|
when Fiber
|
|
187
|
-
|
|
200
|
+
::Monitor.new
|
|
188
201
|
else
|
|
189
202
|
ActiveSupport::Concurrency::NullLock
|
|
190
203
|
end
|
|
191
204
|
end
|
|
192
205
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
def with_instrumenter(instrumenter, &block) # :nodoc:
|
|
197
|
-
Thread.handle_interrupt(EXCEPTION_NEVER) do
|
|
198
|
-
previous_instrumenter = @instrumenter
|
|
199
|
-
@instrumenter = instrumenter
|
|
200
|
-
Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
|
|
201
|
-
ensure
|
|
202
|
-
@instrumenter = previous_instrumenter
|
|
206
|
+
def ensure_writes_are_allowed(sql) # :nodoc:
|
|
207
|
+
if preventing_writes?
|
|
208
|
+
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
|
203
209
|
end
|
|
204
210
|
end
|
|
205
211
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
end
|
|
212
|
+
MAX_JITTER = 0.0..1.0 # :nodoc:
|
|
213
|
+
def max_jitter
|
|
214
|
+
(@config[:pool_jitter] || 0.2).to_f.clamp(MAX_JITTER)
|
|
210
215
|
end
|
|
211
216
|
|
|
212
217
|
def replica?
|
|
@@ -217,6 +222,10 @@ module ActiveRecord
|
|
|
217
222
|
(@config[:connection_retries] || 1).to_i
|
|
218
223
|
end
|
|
219
224
|
|
|
225
|
+
def verify_timeout
|
|
226
|
+
(@config[:verify_timeout] || 2).to_i
|
|
227
|
+
end
|
|
228
|
+
|
|
220
229
|
def retry_deadline
|
|
221
230
|
if @config[:retry_deadline]
|
|
222
231
|
@config[:retry_deadline].to_f
|
|
@@ -235,9 +244,9 @@ module ActiveRecord
|
|
|
235
244
|
# the value of +current_preventing_writes+.
|
|
236
245
|
def preventing_writes?
|
|
237
246
|
return true if replica?
|
|
238
|
-
return false if
|
|
247
|
+
return false if connection_descriptor.nil?
|
|
239
248
|
|
|
240
|
-
|
|
249
|
+
connection_descriptor.current_preventing_writes
|
|
241
250
|
end
|
|
242
251
|
|
|
243
252
|
def prepared_statements?
|
|
@@ -269,7 +278,11 @@ module ActiveRecord
|
|
|
269
278
|
end
|
|
270
279
|
|
|
271
280
|
def valid_type?(type) # :nodoc:
|
|
272
|
-
|
|
281
|
+
self.class.valid_type?(type)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def native_database_types # :nodoc:
|
|
285
|
+
self.class.native_database_types
|
|
273
286
|
end
|
|
274
287
|
|
|
275
288
|
# this method must only be called while holding connection pool's mutex
|
|
@@ -288,8 +301,8 @@ module ActiveRecord
|
|
|
288
301
|
@owner = ActiveSupport::IsolatedExecutionState.context
|
|
289
302
|
end
|
|
290
303
|
|
|
291
|
-
def
|
|
292
|
-
@pool.
|
|
304
|
+
def connection_descriptor # :nodoc:
|
|
305
|
+
@pool.connection_descriptor
|
|
293
306
|
end
|
|
294
307
|
|
|
295
308
|
# The role (e.g. +:writing+) for the current connection. In a
|
|
@@ -308,8 +321,12 @@ module ActiveRecord
|
|
|
308
321
|
@pool.schema_cache || (@schema_cache ||= BoundSchemaReflection.for_lone_connection(@pool.schema_reflection, self))
|
|
309
322
|
end
|
|
310
323
|
|
|
324
|
+
def pool_jitter(duration)
|
|
325
|
+
duration * (1.0 - @pool_jitter)
|
|
326
|
+
end
|
|
327
|
+
|
|
311
328
|
# this method must only be called while holding connection pool's mutex
|
|
312
|
-
def expire
|
|
329
|
+
def expire(update_idle = true) # :nodoc:
|
|
313
330
|
if in_use?
|
|
314
331
|
if @owner != ActiveSupport::IsolatedExecutionState.context
|
|
315
332
|
raise ActiveRecordError, "Cannot expire connection, " \
|
|
@@ -317,8 +334,12 @@ module ActiveRecord
|
|
|
317
334
|
"Current thread: #{ActiveSupport::IsolatedExecutionState.context}."
|
|
318
335
|
end
|
|
319
336
|
|
|
320
|
-
|
|
321
|
-
|
|
337
|
+
_run_checkin_callbacks do
|
|
338
|
+
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC) if update_idle
|
|
339
|
+
@owner = nil
|
|
340
|
+
enable_lazy_transactions!
|
|
341
|
+
unset_query_cache!
|
|
342
|
+
end
|
|
322
343
|
else
|
|
323
344
|
raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
|
|
324
345
|
end
|
|
@@ -343,6 +364,28 @@ module ActiveRecord
|
|
|
343
364
|
Process.clock_gettime(Process::CLOCK_MONOTONIC) - @idle_since
|
|
344
365
|
end
|
|
345
366
|
|
|
367
|
+
# Seconds since this connection last communicated with the server
|
|
368
|
+
def seconds_since_last_activity # :nodoc:
|
|
369
|
+
if @raw_connection && @last_activity
|
|
370
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) - @last_activity
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# Seconds since this connection was established. nil if not
|
|
375
|
+
# connected; infinity if the connection has been explicitly
|
|
376
|
+
# retired.
|
|
377
|
+
def connection_age # :nodoc:
|
|
378
|
+
if @raw_connection && @connected_since
|
|
379
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) - @connected_since
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# Mark the connection as needing to be retired, as if the age has
|
|
384
|
+
# exceeded the maximum allowed.
|
|
385
|
+
def force_retirement # :nodoc:
|
|
386
|
+
@connected_since &&= -Float::INFINITY
|
|
387
|
+
end
|
|
388
|
+
|
|
346
389
|
def unprepared_statement
|
|
347
390
|
cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements
|
|
348
391
|
yield
|
|
@@ -557,6 +600,10 @@ module ActiveRecord
|
|
|
557
600
|
false
|
|
558
601
|
end
|
|
559
602
|
|
|
603
|
+
def supports_disabling_indexes?
|
|
604
|
+
false
|
|
605
|
+
end
|
|
606
|
+
|
|
560
607
|
def return_value_after_insert?(column) # :nodoc:
|
|
561
608
|
column.auto_populated?
|
|
562
609
|
end
|
|
@@ -602,6 +649,11 @@ module ActiveRecord
|
|
|
602
649
|
def drop_virtual_table(*) # :nodoc:
|
|
603
650
|
end
|
|
604
651
|
|
|
652
|
+
# Lock used to read an existing record after a duplicate INSERT in a transaction.
|
|
653
|
+
def create_or_find_by_lock # :nodoc:
|
|
654
|
+
true
|
|
655
|
+
end
|
|
656
|
+
|
|
605
657
|
def advisory_locks_enabled? # :nodoc:
|
|
606
658
|
supports_advisory_locks? && @advisory_locks_enabled
|
|
607
659
|
end
|
|
@@ -666,32 +718,36 @@ module ActiveRecord
|
|
|
666
718
|
deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline
|
|
667
719
|
|
|
668
720
|
@lock.synchronize do
|
|
669
|
-
|
|
721
|
+
attempt_configure_connection do
|
|
722
|
+
@allow_preconnect = false
|
|
670
723
|
|
|
671
|
-
|
|
672
|
-
@raw_connection_dirty = false
|
|
673
|
-
@verified = true
|
|
674
|
-
|
|
675
|
-
reset_transaction(restore: restore_transactions) do
|
|
676
|
-
clear_cache!(new_connection: true)
|
|
677
|
-
configure_connection
|
|
678
|
-
end
|
|
679
|
-
rescue => original_exception
|
|
680
|
-
translated_exception = translate_exception_class(original_exception, nil, nil)
|
|
681
|
-
retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
724
|
+
reconnect
|
|
682
725
|
|
|
683
|
-
|
|
684
|
-
|
|
726
|
+
enable_lazy_transactions!
|
|
727
|
+
@raw_connection_dirty = false
|
|
728
|
+
@last_activity = @connected_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
729
|
+
@verified = true
|
|
730
|
+
@allow_preconnect = true
|
|
685
731
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
732
|
+
reset_transaction(restore: restore_transactions) do
|
|
733
|
+
clear_cache!(new_connection: true)
|
|
734
|
+
configure_connection
|
|
689
735
|
end
|
|
690
|
-
|
|
736
|
+
rescue => original_exception
|
|
737
|
+
translated_exception = translate_exception_class(original_exception, nil, nil)
|
|
738
|
+
retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
691
739
|
|
|
692
|
-
|
|
740
|
+
if !retry_deadline_exceeded && retries_available > 0
|
|
741
|
+
retries_available -= 1
|
|
742
|
+
|
|
743
|
+
if retryable_connection_error?(translated_exception)
|
|
744
|
+
backoff(connection_retries - retries_available)
|
|
745
|
+
retry
|
|
746
|
+
end
|
|
747
|
+
end
|
|
693
748
|
|
|
694
|
-
|
|
749
|
+
raise translated_exception
|
|
750
|
+
end
|
|
695
751
|
end
|
|
696
752
|
end
|
|
697
753
|
|
|
@@ -702,6 +758,9 @@ module ActiveRecord
|
|
|
702
758
|
clear_cache!(new_connection: true)
|
|
703
759
|
reset_transaction
|
|
704
760
|
@raw_connection_dirty = false
|
|
761
|
+
@connected_since = nil
|
|
762
|
+
@last_activity = nil
|
|
763
|
+
@verified = false
|
|
705
764
|
end
|
|
706
765
|
end
|
|
707
766
|
|
|
@@ -724,9 +783,11 @@ module ActiveRecord
|
|
|
724
783
|
# should call super immediately after resetting the connection (and while
|
|
725
784
|
# still holding @lock).
|
|
726
785
|
def reset!
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
786
|
+
attempt_configure_connection do
|
|
787
|
+
clear_cache!(new_connection: true)
|
|
788
|
+
reset_transaction
|
|
789
|
+
configure_connection
|
|
790
|
+
end
|
|
730
791
|
end
|
|
731
792
|
|
|
732
793
|
# Removes the connection from the pool and disconnect it.
|
|
@@ -760,10 +821,14 @@ module ActiveRecord
|
|
|
760
821
|
unless active?
|
|
761
822
|
@lock.synchronize do
|
|
762
823
|
if @unconfigured_connection
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
824
|
+
attempt_configure_connection do
|
|
825
|
+
@raw_connection = @unconfigured_connection
|
|
826
|
+
@unconfigured_connection = nil
|
|
827
|
+
configure_connection
|
|
828
|
+
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
829
|
+
@verified = true
|
|
830
|
+
@allow_preconnect = true
|
|
831
|
+
end
|
|
767
832
|
return
|
|
768
833
|
end
|
|
769
834
|
|
|
@@ -771,6 +836,7 @@ module ActiveRecord
|
|
|
771
836
|
end
|
|
772
837
|
end
|
|
773
838
|
|
|
839
|
+
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
774
840
|
@verified = true
|
|
775
841
|
end
|
|
776
842
|
|
|
@@ -780,8 +846,15 @@ module ActiveRecord
|
|
|
780
846
|
end
|
|
781
847
|
|
|
782
848
|
def clean! # :nodoc:
|
|
783
|
-
|
|
784
|
-
|
|
849
|
+
_run_checkout_callbacks do
|
|
850
|
+
@raw_connection_dirty = false
|
|
851
|
+
@verified = nil
|
|
852
|
+
end
|
|
853
|
+
self
|
|
854
|
+
end
|
|
855
|
+
|
|
856
|
+
def verified? # :nodoc:
|
|
857
|
+
@verified
|
|
785
858
|
end
|
|
786
859
|
|
|
787
860
|
# Provides access to the underlying database driver for this adapter. For
|
|
@@ -869,7 +942,7 @@ module ActiveRecord
|
|
|
869
942
|
def register_class_with_precision(mapping, key, klass, **kwargs) # :nodoc:
|
|
870
943
|
mapping.register_type(key) do |*args|
|
|
871
944
|
precision = extract_precision(args.last)
|
|
872
|
-
klass.new(precision: precision, **kwargs)
|
|
945
|
+
klass.new(precision: precision, **kwargs).freeze
|
|
873
946
|
end
|
|
874
947
|
end
|
|
875
948
|
|
|
@@ -881,6 +954,10 @@ module ActiveRecord
|
|
|
881
954
|
end
|
|
882
955
|
end
|
|
883
956
|
|
|
957
|
+
def valid_type?(type) # :nodoc:
|
|
958
|
+
!native_database_types[type].nil?
|
|
959
|
+
end
|
|
960
|
+
|
|
884
961
|
private
|
|
885
962
|
def initialize_type_map(m)
|
|
886
963
|
register_class_with_limit m, %r(boolean)i, Type::Boolean
|
|
@@ -900,7 +977,7 @@ module ActiveRecord
|
|
|
900
977
|
m.alias_type %r(number)i, "decimal"
|
|
901
978
|
m.alias_type %r(double)i, "float"
|
|
902
979
|
|
|
903
|
-
m.register_type %r(^json)i, Type::Json.new
|
|
980
|
+
m.register_type %r(^json)i, Type::Json.new.freeze
|
|
904
981
|
|
|
905
982
|
m.register_type(%r(decimal)i) do |sql_type|
|
|
906
983
|
scale = extract_scale(sql_type)
|
|
@@ -908,9 +985,9 @@ module ActiveRecord
|
|
|
908
985
|
|
|
909
986
|
if scale == 0
|
|
910
987
|
# FIXME: Remove this class as well
|
|
911
|
-
Type::DecimalWithoutScale.new(precision: precision)
|
|
988
|
+
Type::DecimalWithoutScale.new(precision: precision).freeze
|
|
912
989
|
else
|
|
913
|
-
Type::Decimal.new(precision: precision, scale: scale)
|
|
990
|
+
Type::Decimal.new(precision: precision, scale: scale).freeze
|
|
914
991
|
end
|
|
915
992
|
end
|
|
916
993
|
end
|
|
@@ -918,7 +995,7 @@ module ActiveRecord
|
|
|
918
995
|
def register_class_with_limit(mapping, key, klass)
|
|
919
996
|
mapping.register_type(key) do |*args|
|
|
920
997
|
limit = extract_limit(args.last)
|
|
921
|
-
klass.new(limit: limit)
|
|
998
|
+
klass.new(limit: limit).freeze
|
|
922
999
|
end
|
|
923
1000
|
end
|
|
924
1001
|
|
|
@@ -992,6 +1069,9 @@ module ActiveRecord
|
|
|
992
1069
|
if @verified
|
|
993
1070
|
# Cool, we're confident the connection's ready to use. (Note this might have
|
|
994
1071
|
# become true during the above #materialize_transactions.)
|
|
1072
|
+
elsif (last_activity = seconds_since_last_activity) && last_activity < verify_timeout
|
|
1073
|
+
# We haven't actually verified the connection since we acquired it, but it
|
|
1074
|
+
# has been used very recently. We're going to assume it's still okay.
|
|
995
1075
|
elsif reconnectable
|
|
996
1076
|
if allow_retry
|
|
997
1077
|
# Not sure about the connection yet, but if anything goes wrong we can
|
|
@@ -1033,10 +1113,18 @@ module ActiveRecord
|
|
|
1033
1113
|
# Barring a known-retryable error inside the query (regardless of
|
|
1034
1114
|
# whether we were in a _position_ to retry it), we should infer that
|
|
1035
1115
|
# there's likely a real problem with the connection.
|
|
1116
|
+
@last_activity = nil
|
|
1036
1117
|
@verified = false
|
|
1037
1118
|
end
|
|
1038
1119
|
|
|
1039
1120
|
raise translated_exception
|
|
1121
|
+
rescue Exception
|
|
1122
|
+
# A non-StandardError (a Timeout, or a fiber scheduler's cancel) abandoned
|
|
1123
|
+
# the query partway through, so we mark the connection unverified, just as
|
|
1124
|
+
# a failed query would, forcing a reconnect before it's used again.
|
|
1125
|
+
@last_activity = nil
|
|
1126
|
+
@verified = false
|
|
1127
|
+
raise
|
|
1040
1128
|
ensure
|
|
1041
1129
|
dirty_current_transaction if materialize_transactions
|
|
1042
1130
|
end
|
|
@@ -1047,6 +1135,7 @@ module ActiveRecord
|
|
|
1047
1135
|
# `with_raw_connection` block only when the block is guaranteed to
|
|
1048
1136
|
# exercise the raw connection.
|
|
1049
1137
|
def verified!
|
|
1138
|
+
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
1050
1139
|
@verified = true
|
|
1051
1140
|
end
|
|
1052
1141
|
|
|
@@ -1074,7 +1163,7 @@ module ActiveRecord
|
|
|
1074
1163
|
end
|
|
1075
1164
|
|
|
1076
1165
|
def reconnect
|
|
1077
|
-
raise NotImplementedError
|
|
1166
|
+
raise NotImplementedError.new("#{self.class} should define `reconnect` to implement adapter-specific logic for reconnecting to the database")
|
|
1078
1167
|
end
|
|
1079
1168
|
|
|
1080
1169
|
# Returns a raw connection for internal use with methods that are known
|
|
@@ -1125,16 +1214,18 @@ module ActiveRecord
|
|
|
1125
1214
|
active_record_error
|
|
1126
1215
|
end
|
|
1127
1216
|
|
|
1128
|
-
def log(sql, name = "SQL", binds = [], type_casted_binds = [], async: false, &block) # :doc:
|
|
1129
|
-
|
|
1217
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], async: false, allow_retry: false, &block) # :doc:
|
|
1218
|
+
instrumenter.instrument(
|
|
1130
1219
|
"sql.active_record",
|
|
1131
1220
|
sql: sql,
|
|
1132
1221
|
name: name,
|
|
1133
1222
|
binds: binds,
|
|
1134
1223
|
type_casted_binds: type_casted_binds,
|
|
1135
1224
|
async: async,
|
|
1225
|
+
allow_retry: allow_retry,
|
|
1136
1226
|
connection: self,
|
|
1137
1227
|
transaction: current_transaction.user_transaction.presence,
|
|
1228
|
+
affected_rows: 0,
|
|
1138
1229
|
row_count: 0,
|
|
1139
1230
|
&block
|
|
1140
1231
|
)
|
|
@@ -1142,6 +1233,10 @@ module ActiveRecord
|
|
|
1142
1233
|
raise ex.set_query(sql, binds)
|
|
1143
1234
|
end
|
|
1144
1235
|
|
|
1236
|
+
def instrumenter # :nodoc:
|
|
1237
|
+
ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] ||= ActiveSupport::Notifications.instrumenter
|
|
1238
|
+
end
|
|
1239
|
+
|
|
1145
1240
|
def translate_exception(exception, message:, sql:, binds:)
|
|
1146
1241
|
# override in derived class
|
|
1147
1242
|
case exception
|
|
@@ -1203,6 +1298,13 @@ module ActiveRecord
|
|
|
1203
1298
|
check_version
|
|
1204
1299
|
end
|
|
1205
1300
|
|
|
1301
|
+
def attempt_configure_connection
|
|
1302
|
+
yield
|
|
1303
|
+
rescue Exception # Need to handle things such as Timeout::ExitException
|
|
1304
|
+
disconnect!
|
|
1305
|
+
raise
|
|
1306
|
+
end
|
|
1307
|
+
|
|
1206
1308
|
def default_prepared_statements
|
|
1207
1309
|
true
|
|
1208
1310
|
end
|