activerecord 7.2.2.1 → 8.1.2
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 +564 -753
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/association.rb +35 -11
- data/lib/active_record/associations/belongs_to_association.rb +18 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +17 -4
- 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 +10 -8
- data/lib/active_record/associations/collection_proxy.rb +22 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/associations/join_dependency.rb +4 -2
- data/lib/active_record/associations/preloader/association.rb +2 -2
- 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/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +192 -24
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/primary_key.rb +4 -8
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +17 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
- data/lib/active_record/attribute_methods.rb +24 -19
- data/lib/active_record/attributes.rb +40 -26
- data/lib/active_record/autosave_association.rb +91 -39
- data/lib/active_record/base.rb +3 -4
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +458 -117
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +136 -74
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +44 -11
- data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -29
- data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
- data/lib/active_record/connection_adapters/abstract_adapter.rb +175 -87
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +77 -58
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +73 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -11
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- 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 +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +28 -45
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +140 -64
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +13 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +112 -42
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +2 -19
- data/lib/active_record/connection_adapters.rb +1 -56
- data/lib/active_record/connection_handling.rb +37 -10
- data/lib/active_record/core.rb +61 -25
- data/lib/active_record/counter_cache.rb +34 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/database_configurations/database_config.rb +9 -1
- data/lib/active_record/database_configurations/hash_config.rb +67 -9
- data/lib/active_record/database_configurations/url_config.rb +13 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +19 -19
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +9 -9
- data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
- data/lib/active_record/encryption/encryptor.rb +49 -28
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +9 -2
- data/lib/active_record/enum.rb +46 -42
- data/lib/active_record/errors.rb +36 -12
- 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 +73 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +2 -4
- data/lib/active_record/future_result.rb +13 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/insert_all.rb +12 -7
- data/lib/active_record/locking/optimistic.rb +8 -1
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +3 -13
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +44 -11
- data/lib/active_record/migration/compatibility.rb +37 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +50 -43
- data/lib/active_record/model_schema.rb +38 -13
- data/lib/active_record/nested_attributes.rb +6 -6
- data/lib/active_record/persistence.rb +162 -133
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +104 -52
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +12 -12
- data/lib/active_record/railtie.rb +37 -32
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +26 -37
- 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 +53 -21
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +147 -73
- data/lib/active_record/relation/calculations.rb +80 -63
- data/lib/active_record/relation/delegation.rb +25 -15
- data/lib/active_record/relation/finder_methods.rb +54 -37
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +22 -7
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +156 -95
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +10 -11
- data/lib/active_record/relation.rb +122 -80
- data/lib/active_record/result.rb +109 -24
- data/lib/active_record/runtime_registry.rb +42 -58
- data/lib/active_record/sanitization.rb +9 -6
- data/lib/active_record/schema_dumper.rb +47 -22
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +47 -18
- data/lib/active_record/statement_cache.rb +24 -20
- data/lib/active_record/store.rb +51 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +6 -23
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +85 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +39 -2
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +39 -16
- 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 +15 -2
- data/lib/active_record/type/serialized.rb +11 -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/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +85 -50
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/collectors/bind.rb +2 -2
- 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/select_manager.rb +13 -4
- data/lib/arel/table.rb +3 -7
- 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 +6 -22
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +17 -17
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -163
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "set"
|
|
4
3
|
require "active_record/connection_adapters/sql_type_metadata"
|
|
5
4
|
require "active_record/connection_adapters/abstract/schema_dumper"
|
|
6
5
|
require "active_record/connection_adapters/abstract/schema_creation"
|
|
7
6
|
require "active_support/concurrency/null_lock"
|
|
8
7
|
require "active_support/concurrency/load_interlock_aware_monitor"
|
|
8
|
+
require "active_support/concurrency/thread_monitor"
|
|
9
9
|
require "arel/collectors/bind"
|
|
10
10
|
require "arel/collectors/composite"
|
|
11
11
|
require "arel/collectors/sql_string"
|
|
@@ -43,6 +43,8 @@ module ActiveRecord
|
|
|
43
43
|
|
|
44
44
|
attr_reader :pool
|
|
45
45
|
attr_reader :visitor, :owner, :logger, :lock
|
|
46
|
+
attr_reader :allow_preconnect # :nodoc:
|
|
47
|
+
attr_accessor :pinned # :nodoc:
|
|
46
48
|
alias :in_use? :owner
|
|
47
49
|
|
|
48
50
|
def pool=(value)
|
|
@@ -51,7 +53,11 @@ module ActiveRecord
|
|
|
51
53
|
@pool = value
|
|
52
54
|
end
|
|
53
55
|
|
|
54
|
-
|
|
56
|
+
def allow_preconnect=(value) # :nodoc:
|
|
57
|
+
@lock.synchronize do
|
|
58
|
+
@allow_preconnect = value
|
|
59
|
+
end
|
|
60
|
+
end
|
|
55
61
|
|
|
56
62
|
def self.type_cast_config_to_integer(config)
|
|
57
63
|
if config.is_a?(Integer)
|
|
@@ -120,7 +126,7 @@ module ActiveRecord
|
|
|
120
126
|
|
|
121
127
|
# Opens a database console session.
|
|
122
128
|
def self.dbconsole(config, options = {})
|
|
123
|
-
raise NotImplementedError
|
|
129
|
+
raise NotImplementedError.new("#{self.class} should define `dbconsole` that accepts a db config and options to implement connecting to the db console")
|
|
124
130
|
end
|
|
125
131
|
|
|
126
132
|
def initialize(config_or_deprecated_connection, deprecated_logger = nil, deprecated_connection_options = nil, deprecated_config = nil) # :nodoc:
|
|
@@ -128,6 +134,7 @@ module ActiveRecord
|
|
|
128
134
|
|
|
129
135
|
@raw_connection = nil
|
|
130
136
|
@unconfigured_connection = nil
|
|
137
|
+
@connected_since = nil
|
|
131
138
|
|
|
132
139
|
if config_or_deprecated_connection.is_a?(Hash)
|
|
133
140
|
@config = config_or_deprecated_connection.symbolize_keys
|
|
@@ -140,6 +147,7 @@ module ActiveRecord
|
|
|
140
147
|
# Soft-deprecated for now; we'll probably warn in future.
|
|
141
148
|
|
|
142
149
|
@unconfigured_connection = config_or_deprecated_connection
|
|
150
|
+
@connected_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
143
151
|
@logger = deprecated_logger || ActiveRecord::Base.logger
|
|
144
152
|
if deprecated_config
|
|
145
153
|
@config = (deprecated_config || {}).symbolize_keys
|
|
@@ -151,9 +159,10 @@ module ActiveRecord
|
|
|
151
159
|
end
|
|
152
160
|
|
|
153
161
|
@owner = nil
|
|
154
|
-
@
|
|
162
|
+
@pinned = false
|
|
155
163
|
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
|
156
164
|
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
165
|
+
@allow_preconnect = false
|
|
157
166
|
@visitor = arel_visitor
|
|
158
167
|
@statements = build_statement_pool
|
|
159
168
|
self.lock_thread = nil
|
|
@@ -169,7 +178,10 @@ module ActiveRecord
|
|
|
169
178
|
@default_timezone = self.class.validate_default_timezone(@config[:default_timezone])
|
|
170
179
|
|
|
171
180
|
@raw_connection_dirty = false
|
|
181
|
+
@last_activity = nil
|
|
172
182
|
@verified = false
|
|
183
|
+
|
|
184
|
+
@pool_jitter = rand * max_jitter
|
|
173
185
|
end
|
|
174
186
|
|
|
175
187
|
def inspect # :nodoc:
|
|
@@ -183,31 +195,23 @@ module ActiveRecord
|
|
|
183
195
|
@lock =
|
|
184
196
|
case lock_thread
|
|
185
197
|
when Thread
|
|
186
|
-
ActiveSupport::Concurrency::
|
|
198
|
+
ActiveSupport::Concurrency::ThreadMonitor.new
|
|
187
199
|
when Fiber
|
|
188
|
-
|
|
200
|
+
::Monitor.new
|
|
189
201
|
else
|
|
190
202
|
ActiveSupport::Concurrency::NullLock
|
|
191
203
|
end
|
|
192
204
|
end
|
|
193
205
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
def with_instrumenter(instrumenter, &block) # :nodoc:
|
|
198
|
-
Thread.handle_interrupt(EXCEPTION_NEVER) do
|
|
199
|
-
previous_instrumenter = @instrumenter
|
|
200
|
-
@instrumenter = instrumenter
|
|
201
|
-
Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
|
|
202
|
-
ensure
|
|
203
|
-
@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}"
|
|
204
209
|
end
|
|
205
210
|
end
|
|
206
211
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
end
|
|
212
|
+
MAX_JITTER = 0.0..1.0 # :nodoc:
|
|
213
|
+
def max_jitter
|
|
214
|
+
(@config[:pool_jitter] || 0.2).to_f.clamp(MAX_JITTER)
|
|
211
215
|
end
|
|
212
216
|
|
|
213
217
|
def replica?
|
|
@@ -218,6 +222,10 @@ module ActiveRecord
|
|
|
218
222
|
(@config[:connection_retries] || 1).to_i
|
|
219
223
|
end
|
|
220
224
|
|
|
225
|
+
def verify_timeout
|
|
226
|
+
(@config[:verify_timeout] || 2).to_i
|
|
227
|
+
end
|
|
228
|
+
|
|
221
229
|
def retry_deadline
|
|
222
230
|
if @config[:retry_deadline]
|
|
223
231
|
@config[:retry_deadline].to_f
|
|
@@ -236,9 +244,9 @@ module ActiveRecord
|
|
|
236
244
|
# the value of +current_preventing_writes+.
|
|
237
245
|
def preventing_writes?
|
|
238
246
|
return true if replica?
|
|
239
|
-
return false if
|
|
247
|
+
return false if connection_descriptor.nil?
|
|
240
248
|
|
|
241
|
-
|
|
249
|
+
connection_descriptor.current_preventing_writes
|
|
242
250
|
end
|
|
243
251
|
|
|
244
252
|
def prepared_statements?
|
|
@@ -270,7 +278,11 @@ module ActiveRecord
|
|
|
270
278
|
end
|
|
271
279
|
|
|
272
280
|
def valid_type?(type) # :nodoc:
|
|
273
|
-
|
|
281
|
+
self.class.valid_type?(type)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def native_database_types # :nodoc:
|
|
285
|
+
self.class.native_database_types
|
|
274
286
|
end
|
|
275
287
|
|
|
276
288
|
# this method must only be called while holding connection pool's mutex
|
|
@@ -289,8 +301,8 @@ module ActiveRecord
|
|
|
289
301
|
@owner = ActiveSupport::IsolatedExecutionState.context
|
|
290
302
|
end
|
|
291
303
|
|
|
292
|
-
def
|
|
293
|
-
@pool.
|
|
304
|
+
def connection_descriptor # :nodoc:
|
|
305
|
+
@pool.connection_descriptor
|
|
294
306
|
end
|
|
295
307
|
|
|
296
308
|
# The role (e.g. +:writing+) for the current connection. In a
|
|
@@ -309,8 +321,12 @@ module ActiveRecord
|
|
|
309
321
|
@pool.schema_cache || (@schema_cache ||= BoundSchemaReflection.for_lone_connection(@pool.schema_reflection, self))
|
|
310
322
|
end
|
|
311
323
|
|
|
324
|
+
def pool_jitter(duration)
|
|
325
|
+
duration * (1.0 - @pool_jitter)
|
|
326
|
+
end
|
|
327
|
+
|
|
312
328
|
# this method must only be called while holding connection pool's mutex
|
|
313
|
-
def expire
|
|
329
|
+
def expire(update_idle = true) # :nodoc:
|
|
314
330
|
if in_use?
|
|
315
331
|
if @owner != ActiveSupport::IsolatedExecutionState.context
|
|
316
332
|
raise ActiveRecordError, "Cannot expire connection, " \
|
|
@@ -318,8 +334,12 @@ module ActiveRecord
|
|
|
318
334
|
"Current thread: #{ActiveSupport::IsolatedExecutionState.context}."
|
|
319
335
|
end
|
|
320
336
|
|
|
321
|
-
|
|
322
|
-
|
|
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
|
|
323
343
|
else
|
|
324
344
|
raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
|
|
325
345
|
end
|
|
@@ -344,6 +364,28 @@ module ActiveRecord
|
|
|
344
364
|
Process.clock_gettime(Process::CLOCK_MONOTONIC) - @idle_since
|
|
345
365
|
end
|
|
346
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
|
+
|
|
347
389
|
def unprepared_statement
|
|
348
390
|
cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements
|
|
349
391
|
yield
|
|
@@ -558,6 +600,10 @@ module ActiveRecord
|
|
|
558
600
|
false
|
|
559
601
|
end
|
|
560
602
|
|
|
603
|
+
def supports_disabling_indexes?
|
|
604
|
+
false
|
|
605
|
+
end
|
|
606
|
+
|
|
561
607
|
def return_value_after_insert?(column) # :nodoc:
|
|
562
608
|
column.auto_populated?
|
|
563
609
|
end
|
|
@@ -576,23 +622,31 @@ module ActiveRecord
|
|
|
576
622
|
end
|
|
577
623
|
|
|
578
624
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
579
|
-
def create_enum(
|
|
625
|
+
def create_enum(...) # :nodoc:
|
|
580
626
|
end
|
|
581
627
|
|
|
582
628
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
583
|
-
def drop_enum(
|
|
629
|
+
def drop_enum(...) # :nodoc:
|
|
584
630
|
end
|
|
585
631
|
|
|
586
632
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
587
|
-
def rename_enum(
|
|
633
|
+
def rename_enum(...) # :nodoc:
|
|
588
634
|
end
|
|
589
635
|
|
|
590
636
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
591
|
-
def add_enum_value(
|
|
637
|
+
def add_enum_value(...) # :nodoc:
|
|
592
638
|
end
|
|
593
639
|
|
|
594
640
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
595
|
-
def rename_enum_value(
|
|
641
|
+
def rename_enum_value(...) # :nodoc:
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
# This is meant to be implemented by the adapters that support virtual tables
|
|
645
|
+
def create_virtual_table(*) # :nodoc:
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
# This is meant to be implemented by the adapters that support virtual tables
|
|
649
|
+
def drop_virtual_table(*) # :nodoc:
|
|
596
650
|
end
|
|
597
651
|
|
|
598
652
|
def advisory_locks_enabled? # :nodoc:
|
|
@@ -659,32 +713,36 @@ module ActiveRecord
|
|
|
659
713
|
deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline
|
|
660
714
|
|
|
661
715
|
@lock.synchronize do
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
enable_lazy_transactions!
|
|
665
|
-
@raw_connection_dirty = false
|
|
666
|
-
@verified = true
|
|
716
|
+
attempt_configure_connection do
|
|
717
|
+
@allow_preconnect = false
|
|
667
718
|
|
|
668
|
-
|
|
669
|
-
clear_cache!(new_connection: true)
|
|
670
|
-
configure_connection
|
|
671
|
-
end
|
|
672
|
-
rescue => original_exception
|
|
673
|
-
translated_exception = translate_exception_class(original_exception, nil, nil)
|
|
674
|
-
retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
719
|
+
reconnect
|
|
675
720
|
|
|
676
|
-
|
|
677
|
-
|
|
721
|
+
enable_lazy_transactions!
|
|
722
|
+
@raw_connection_dirty = false
|
|
723
|
+
@last_activity = @connected_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
724
|
+
@verified = true
|
|
725
|
+
@allow_preconnect = true
|
|
678
726
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
727
|
+
reset_transaction(restore: restore_transactions) do
|
|
728
|
+
clear_cache!(new_connection: true)
|
|
729
|
+
configure_connection
|
|
682
730
|
end
|
|
683
|
-
|
|
731
|
+
rescue => original_exception
|
|
732
|
+
translated_exception = translate_exception_class(original_exception, nil, nil)
|
|
733
|
+
retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
684
734
|
|
|
685
|
-
|
|
735
|
+
if !retry_deadline_exceeded && retries_available > 0
|
|
736
|
+
retries_available -= 1
|
|
686
737
|
|
|
687
|
-
|
|
738
|
+
if retryable_connection_error?(translated_exception)
|
|
739
|
+
backoff(connection_retries - retries_available)
|
|
740
|
+
retry
|
|
741
|
+
end
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
raise translated_exception
|
|
745
|
+
end
|
|
688
746
|
end
|
|
689
747
|
end
|
|
690
748
|
|
|
@@ -695,6 +753,9 @@ module ActiveRecord
|
|
|
695
753
|
clear_cache!(new_connection: true)
|
|
696
754
|
reset_transaction
|
|
697
755
|
@raw_connection_dirty = false
|
|
756
|
+
@connected_since = nil
|
|
757
|
+
@last_activity = nil
|
|
758
|
+
@verified = false
|
|
698
759
|
end
|
|
699
760
|
end
|
|
700
761
|
|
|
@@ -717,9 +778,11 @@ module ActiveRecord
|
|
|
717
778
|
# should call super immediately after resetting the connection (and while
|
|
718
779
|
# still holding @lock).
|
|
719
780
|
def reset!
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
781
|
+
attempt_configure_connection do
|
|
782
|
+
clear_cache!(new_connection: true)
|
|
783
|
+
reset_transaction
|
|
784
|
+
configure_connection
|
|
785
|
+
end
|
|
723
786
|
end
|
|
724
787
|
|
|
725
788
|
# Removes the connection from the pool and disconnect it.
|
|
@@ -753,10 +816,14 @@ module ActiveRecord
|
|
|
753
816
|
unless active?
|
|
754
817
|
@lock.synchronize do
|
|
755
818
|
if @unconfigured_connection
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
819
|
+
attempt_configure_connection do
|
|
820
|
+
@raw_connection = @unconfigured_connection
|
|
821
|
+
@unconfigured_connection = nil
|
|
822
|
+
configure_connection
|
|
823
|
+
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
824
|
+
@verified = true
|
|
825
|
+
@allow_preconnect = true
|
|
826
|
+
end
|
|
760
827
|
return
|
|
761
828
|
end
|
|
762
829
|
|
|
@@ -764,6 +831,7 @@ module ActiveRecord
|
|
|
764
831
|
end
|
|
765
832
|
end
|
|
766
833
|
|
|
834
|
+
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
767
835
|
@verified = true
|
|
768
836
|
end
|
|
769
837
|
|
|
@@ -773,8 +841,15 @@ module ActiveRecord
|
|
|
773
841
|
end
|
|
774
842
|
|
|
775
843
|
def clean! # :nodoc:
|
|
776
|
-
|
|
777
|
-
|
|
844
|
+
_run_checkout_callbacks do
|
|
845
|
+
@raw_connection_dirty = false
|
|
846
|
+
@verified = nil
|
|
847
|
+
end
|
|
848
|
+
self
|
|
849
|
+
end
|
|
850
|
+
|
|
851
|
+
def verified? # :nodoc:
|
|
852
|
+
@verified
|
|
778
853
|
end
|
|
779
854
|
|
|
780
855
|
# Provides access to the underlying database driver for this adapter. For
|
|
@@ -862,7 +937,7 @@ module ActiveRecord
|
|
|
862
937
|
def register_class_with_precision(mapping, key, klass, **kwargs) # :nodoc:
|
|
863
938
|
mapping.register_type(key) do |*args|
|
|
864
939
|
precision = extract_precision(args.last)
|
|
865
|
-
klass.new(precision: precision, **kwargs)
|
|
940
|
+
klass.new(precision: precision, **kwargs).freeze
|
|
866
941
|
end
|
|
867
942
|
end
|
|
868
943
|
|
|
@@ -874,6 +949,10 @@ module ActiveRecord
|
|
|
874
949
|
end
|
|
875
950
|
end
|
|
876
951
|
|
|
952
|
+
def valid_type?(type) # :nodoc:
|
|
953
|
+
!native_database_types[type].nil?
|
|
954
|
+
end
|
|
955
|
+
|
|
877
956
|
private
|
|
878
957
|
def initialize_type_map(m)
|
|
879
958
|
register_class_with_limit m, %r(boolean)i, Type::Boolean
|
|
@@ -893,7 +972,7 @@ module ActiveRecord
|
|
|
893
972
|
m.alias_type %r(number)i, "decimal"
|
|
894
973
|
m.alias_type %r(double)i, "float"
|
|
895
974
|
|
|
896
|
-
m.register_type %r(^json)i, Type::Json.new
|
|
975
|
+
m.register_type %r(^json)i, Type::Json.new.freeze
|
|
897
976
|
|
|
898
977
|
m.register_type(%r(decimal)i) do |sql_type|
|
|
899
978
|
scale = extract_scale(sql_type)
|
|
@@ -901,9 +980,9 @@ module ActiveRecord
|
|
|
901
980
|
|
|
902
981
|
if scale == 0
|
|
903
982
|
# FIXME: Remove this class as well
|
|
904
|
-
Type::DecimalWithoutScale.new(precision: precision)
|
|
983
|
+
Type::DecimalWithoutScale.new(precision: precision).freeze
|
|
905
984
|
else
|
|
906
|
-
Type::Decimal.new(precision: precision, scale: scale)
|
|
985
|
+
Type::Decimal.new(precision: precision, scale: scale).freeze
|
|
907
986
|
end
|
|
908
987
|
end
|
|
909
988
|
end
|
|
@@ -911,7 +990,7 @@ module ActiveRecord
|
|
|
911
990
|
def register_class_with_limit(mapping, key, klass)
|
|
912
991
|
mapping.register_type(key) do |*args|
|
|
913
992
|
limit = extract_limit(args.last)
|
|
914
|
-
klass.new(limit: limit)
|
|
993
|
+
klass.new(limit: limit).freeze
|
|
915
994
|
end
|
|
916
995
|
end
|
|
917
996
|
|
|
@@ -985,6 +1064,9 @@ module ActiveRecord
|
|
|
985
1064
|
if @verified
|
|
986
1065
|
# Cool, we're confident the connection's ready to use. (Note this might have
|
|
987
1066
|
# become true during the above #materialize_transactions.)
|
|
1067
|
+
elsif (last_activity = seconds_since_last_activity) && last_activity < verify_timeout
|
|
1068
|
+
# We haven't actually verified the connection since we acquired it, but it
|
|
1069
|
+
# has been used very recently. We're going to assume it's still okay.
|
|
988
1070
|
elsif reconnectable
|
|
989
1071
|
if allow_retry
|
|
990
1072
|
# Not sure about the connection yet, but if anything goes wrong we can
|
|
@@ -1026,6 +1108,7 @@ module ActiveRecord
|
|
|
1026
1108
|
# Barring a known-retryable error inside the query (regardless of
|
|
1027
1109
|
# whether we were in a _position_ to retry it), we should infer that
|
|
1028
1110
|
# there's likely a real problem with the connection.
|
|
1111
|
+
@last_activity = nil
|
|
1029
1112
|
@verified = false
|
|
1030
1113
|
end
|
|
1031
1114
|
|
|
@@ -1040,11 +1123,13 @@ module ActiveRecord
|
|
|
1040
1123
|
# `with_raw_connection` block only when the block is guaranteed to
|
|
1041
1124
|
# exercise the raw connection.
|
|
1042
1125
|
def verified!
|
|
1126
|
+
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
1043
1127
|
@verified = true
|
|
1044
1128
|
end
|
|
1045
1129
|
|
|
1046
1130
|
def retryable_connection_error?(exception)
|
|
1047
|
-
exception.is_a?(ConnectionNotEstablished)
|
|
1131
|
+
(exception.is_a?(ConnectionNotEstablished) && !exception.is_a?(ConnectionNotDefined)) ||
|
|
1132
|
+
exception.is_a?(ConnectionFailed)
|
|
1048
1133
|
end
|
|
1049
1134
|
|
|
1050
1135
|
def invalidate_transaction(exception)
|
|
@@ -1066,7 +1151,7 @@ module ActiveRecord
|
|
|
1066
1151
|
end
|
|
1067
1152
|
|
|
1068
1153
|
def reconnect
|
|
1069
|
-
raise NotImplementedError
|
|
1154
|
+
raise NotImplementedError.new("#{self.class} should define `reconnect` to implement adapter-specific logic for reconnecting to the database")
|
|
1070
1155
|
end
|
|
1071
1156
|
|
|
1072
1157
|
# Returns a raw connection for internal use with methods that are known
|
|
@@ -1105,27 +1190,30 @@ module ActiveRecord
|
|
|
1105
1190
|
end
|
|
1106
1191
|
end
|
|
1107
1192
|
|
|
1108
|
-
def translate_exception_class(
|
|
1109
|
-
|
|
1193
|
+
def translate_exception_class(native_error, sql, binds)
|
|
1194
|
+
return native_error if native_error.is_a?(ActiveRecordError)
|
|
1195
|
+
|
|
1196
|
+
message = "#{native_error.class.name}: #{native_error.message}"
|
|
1110
1197
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1198
|
+
active_record_error = translate_exception(
|
|
1199
|
+
native_error, message: message, sql: sql, binds: binds
|
|
1113
1200
|
)
|
|
1114
|
-
|
|
1115
|
-
|
|
1201
|
+
active_record_error.set_backtrace(native_error.backtrace)
|
|
1202
|
+
active_record_error
|
|
1116
1203
|
end
|
|
1117
1204
|
|
|
1118
|
-
def log(sql, name = "SQL", binds = [], type_casted_binds = [],
|
|
1119
|
-
|
|
1205
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], async: false, allow_retry: false, &block) # :doc:
|
|
1206
|
+
instrumenter.instrument(
|
|
1120
1207
|
"sql.active_record",
|
|
1121
1208
|
sql: sql,
|
|
1122
1209
|
name: name,
|
|
1123
1210
|
binds: binds,
|
|
1124
1211
|
type_casted_binds: type_casted_binds,
|
|
1125
|
-
statement_name: statement_name,
|
|
1126
1212
|
async: async,
|
|
1213
|
+
allow_retry: allow_retry,
|
|
1127
1214
|
connection: self,
|
|
1128
1215
|
transaction: current_transaction.user_transaction.presence,
|
|
1216
|
+
affected_rows: 0,
|
|
1129
1217
|
row_count: 0,
|
|
1130
1218
|
&block
|
|
1131
1219
|
)
|
|
@@ -1133,11 +1221,8 @@ module ActiveRecord
|
|
|
1133
1221
|
raise ex.set_query(sql, binds)
|
|
1134
1222
|
end
|
|
1135
1223
|
|
|
1136
|
-
def
|
|
1137
|
-
|
|
1138
|
-
sql = transformer.call(sql, self)
|
|
1139
|
-
end
|
|
1140
|
-
sql
|
|
1224
|
+
def instrumenter # :nodoc:
|
|
1225
|
+
ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] ||= ActiveSupport::Notifications.instrumenter
|
|
1141
1226
|
end
|
|
1142
1227
|
|
|
1143
1228
|
def translate_exception(exception, message:, sql:, binds:)
|
|
@@ -1150,10 +1235,6 @@ module ActiveRecord
|
|
|
1150
1235
|
end
|
|
1151
1236
|
end
|
|
1152
1237
|
|
|
1153
|
-
def without_prepared_statement?(binds)
|
|
1154
|
-
!prepared_statements || binds.empty?
|
|
1155
|
-
end
|
|
1156
|
-
|
|
1157
1238
|
def column_for(table_name, column_name)
|
|
1158
1239
|
column_name = column_name.to_s
|
|
1159
1240
|
columns(table_name).detect { |c| c.name == column_name } ||
|
|
@@ -1205,6 +1286,13 @@ module ActiveRecord
|
|
|
1205
1286
|
check_version
|
|
1206
1287
|
end
|
|
1207
1288
|
|
|
1289
|
+
def attempt_configure_connection
|
|
1290
|
+
yield
|
|
1291
|
+
rescue Exception # Need to handle things such as Timeout::ExitException
|
|
1292
|
+
disconnect!
|
|
1293
|
+
raise
|
|
1294
|
+
end
|
|
1295
|
+
|
|
1208
1296
|
def default_prepared_statements
|
|
1209
1297
|
true
|
|
1210
1298
|
end
|