activerecord 7.1.3.4 → 7.2.0.beta2
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 +514 -2126
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +9 -8
- data/lib/active_record/associations/belongs_to_association.rb +18 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/collection_association.rb +4 -2
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/has_many_association.rb +3 -3
- data/lib/active_record/associations/has_one_association.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
- data/lib/active_record/associations/join_dependency.rb +5 -7
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +2 -1
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +34 -11
- data/lib/active_record/attribute_assignment.rb +1 -11
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +1 -1
- data/lib/active_record/attribute_methods/primary_key.rb +23 -55
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +4 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -6
- data/lib/active_record/attribute_methods.rb +87 -58
- data/lib/active_record/attributes.rb +55 -42
- data/lib/active_record/autosave_association.rb +14 -30
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +248 -58
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +35 -18
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +161 -75
- data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +22 -9
- data/lib/active_record/connection_adapters/abstract/transaction.rb +65 -60
- data/lib/active_record/connection_adapters/abstract_adapter.rb +33 -61
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +69 -19
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -0
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +11 -5
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -32
- data/lib/active_record/connection_adapters/pool_config.rb +7 -6
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +16 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +26 -21
- data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +44 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +25 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +109 -77
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +12 -6
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +32 -65
- data/lib/active_record/connection_adapters.rb +121 -0
- data/lib/active_record/connection_handling.rb +56 -41
- data/lib/active_record/core.rb +59 -38
- data/lib/active_record/counter_cache.rb +23 -10
- data/lib/active_record/database_configurations/connection_url_resolver.rb +7 -2
- data/lib/active_record/database_configurations/database_config.rb +15 -4
- data/lib/active_record/database_configurations/hash_config.rb +44 -36
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +30 -6
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/encryptable_record.rb +2 -2
- data/lib/active_record/encryption/encrypted_attribute_type.rb +24 -4
- data/lib/active_record/encryption/encryptor.rb +17 -2
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +8 -4
- data/lib/active_record/enum.rb +11 -2
- data/lib/active_record/errors.rb +16 -11
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -31
- data/lib/active_record/future_result.rb +17 -4
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +18 -15
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/log_subscriber.rb +0 -21
- data/lib/active_record/marshalling.rb +1 -1
- data/lib/active_record/message_pack.rb +2 -2
- data/lib/active_record/migration/command_recorder.rb +2 -3
- data/lib/active_record/migration/compatibility.rb +11 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +85 -76
- data/lib/active_record/model_schema.rb +34 -69
- data/lib/active_record/nested_attributes.rb +11 -3
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +32 -354
- data/lib/active_record/query_cache.rb +18 -6
- data/lib/active_record/query_logs.rb +15 -0
- data/lib/active_record/query_logs_formatter.rb +1 -1
- data/lib/active_record/querying.rb +21 -9
- data/lib/active_record/railtie.rb +52 -64
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +41 -44
- data/lib/active_record/reflection.rb +98 -37
- data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +94 -61
- data/lib/active_record/relation/delegation.rb +8 -11
- data/lib/active_record/relation/finder_methods.rb +16 -2
- data/lib/active_record/relation/merger.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +6 -1
- data/lib/active_record/relation/predicate_builder.rb +3 -3
- data/lib/active_record/relation/query_methods.rb +197 -44
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +2 -18
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +500 -66
- data/lib/active_record/result.rb +32 -45
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +24 -19
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +19 -9
- data/lib/active_record/schema_migration.rb +30 -14
- data/lib/active_record/signed_id.rb +11 -1
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/table_metadata.rb +1 -10
- data/lib/active_record/tasks/database_tasks.rb +70 -42
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
- data/lib/active_record/test_fixtures.rb +82 -91
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +131 -0
- data/lib/active_record/transactions.rb +70 -14
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +14 -10
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +149 -40
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/nodes/binary.rb +0 -6
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +4 -3
- data/lib/arel/nodes/sql_literal.rb +7 -0
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/to_sql.rb +31 -17
- data/lib/arel.rb +7 -3
- metadata +17 -12
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/digest"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module ConnectionAdapters
|
5
7
|
# = Active Record Connection Adapters Transaction State
|
@@ -107,6 +109,7 @@ module ActiveRecord
|
|
107
109
|
def initialize; end
|
108
110
|
def state; end
|
109
111
|
def closed?; true; end
|
112
|
+
alias_method :blank?, :closed?
|
110
113
|
def open?; false; end
|
111
114
|
def joinable?; false; end
|
112
115
|
def add_record(record, _ = true); end
|
@@ -115,15 +118,21 @@ module ActiveRecord
|
|
115
118
|
def dirty!; end
|
116
119
|
def invalidated?; false; end
|
117
120
|
def invalidate!; end
|
121
|
+
def materialized?; false; end
|
122
|
+
def before_commit; yield; end
|
123
|
+
def after_commit; yield; end
|
124
|
+
def after_rollback; end # noop
|
125
|
+
def uuid; Digest::UUID.nil_uuid; end
|
118
126
|
end
|
119
127
|
|
120
|
-
class Transaction # :nodoc:
|
128
|
+
class Transaction < ActiveRecord::Transaction # :nodoc:
|
121
129
|
attr_reader :connection, :state, :savepoint_name, :isolation_level
|
122
130
|
attr_accessor :written
|
123
131
|
|
124
132
|
delegate :invalidate!, :invalidated?, to: :@state
|
125
133
|
|
126
134
|
def initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false)
|
135
|
+
super()
|
127
136
|
@connection = connection
|
128
137
|
@state = TransactionState.new
|
129
138
|
@records = nil
|
@@ -133,7 +142,7 @@ module ActiveRecord
|
|
133
142
|
@run_commit_callbacks = run_commit_callbacks
|
134
143
|
@lazy_enrollment_records = nil
|
135
144
|
@dirty = false
|
136
|
-
@instrumenter = TransactionInstrumenter.new(connection: connection)
|
145
|
+
@instrumenter = TransactionInstrumenter.new(connection: connection, transaction: self)
|
137
146
|
end
|
138
147
|
|
139
148
|
def dirty!
|
@@ -190,66 +199,80 @@ module ActiveRecord
|
|
190
199
|
end
|
191
200
|
|
192
201
|
def rollback_records
|
193
|
-
|
194
|
-
|
195
|
-
|
202
|
+
if records
|
203
|
+
begin
|
204
|
+
ite = unique_records
|
196
205
|
|
197
|
-
|
206
|
+
instances_to_run_callbacks_on = prepare_instances_to_run_callbacks_on(ite)
|
198
207
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
208
|
+
run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks|
|
209
|
+
record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks)
|
210
|
+
end
|
211
|
+
ensure
|
212
|
+
ite&.each do |i|
|
213
|
+
i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
|
214
|
+
end
|
215
|
+
end
|
205
216
|
end
|
217
|
+
|
218
|
+
@callbacks&.each(&:after_rollback)
|
206
219
|
end
|
207
220
|
|
208
221
|
def before_commit_records
|
209
|
-
return unless records
|
210
|
-
|
211
222
|
if @run_commit_callbacks
|
212
|
-
if
|
213
|
-
|
223
|
+
if records
|
224
|
+
if ActiveRecord.before_committed_on_all_records
|
225
|
+
ite = unique_records
|
214
226
|
|
215
|
-
|
216
|
-
|
217
|
-
|
227
|
+
instances_to_run_callbacks_on = records.each_with_object({}) do |record, candidates|
|
228
|
+
candidates[record] = record
|
229
|
+
end
|
218
230
|
|
219
|
-
|
220
|
-
|
231
|
+
run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks|
|
232
|
+
record.before_committed! if should_run_callbacks
|
233
|
+
end
|
234
|
+
else
|
235
|
+
records.uniq.each(&:before_committed!)
|
221
236
|
end
|
222
|
-
else
|
223
|
-
records.uniq.each(&:before_committed!)
|
224
237
|
end
|
238
|
+
|
239
|
+
@callbacks&.each(&:before_commit)
|
225
240
|
end
|
241
|
+
# Note: When @run_commit_callbacks is false #commit_records takes care of appending
|
242
|
+
# remaining callbacks to the parent transaction
|
226
243
|
end
|
227
244
|
|
228
245
|
def commit_records
|
229
|
-
|
230
|
-
|
231
|
-
|
246
|
+
if records
|
247
|
+
begin
|
248
|
+
ite = unique_records
|
232
249
|
|
233
|
-
|
234
|
-
|
250
|
+
if @run_commit_callbacks
|
251
|
+
instances_to_run_callbacks_on = prepare_instances_to_run_callbacks_on(ite)
|
235
252
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
253
|
+
run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks|
|
254
|
+
record.committed!(should_run_callbacks: should_run_callbacks)
|
255
|
+
end
|
256
|
+
else
|
257
|
+
while record = ite.shift
|
258
|
+
# if not running callbacks, only adds the record to the parent transaction
|
259
|
+
connection.add_transaction_record(record)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
ensure
|
263
|
+
ite&.each { |i| i.committed!(should_run_callbacks: false) }
|
243
264
|
end
|
244
265
|
end
|
245
|
-
|
246
|
-
|
266
|
+
|
267
|
+
if @run_commit_callbacks
|
268
|
+
@callbacks&.each(&:after_commit)
|
269
|
+
elsif @callbacks
|
270
|
+
connection.current_transaction.append_callbacks(@callbacks)
|
271
|
+
end
|
247
272
|
end
|
248
273
|
|
249
274
|
def full_rollback?; true; end
|
250
275
|
def joinable?; @joinable; end
|
251
|
-
def closed?; false; end
|
252
|
-
def open?; !closed?; end
|
253
276
|
|
254
277
|
private
|
255
278
|
def unique_records
|
@@ -349,7 +372,7 @@ module ActiveRecord
|
|
349
372
|
|
350
373
|
def rollback
|
351
374
|
unless @state.invalidated?
|
352
|
-
connection.rollback_to_savepoint(savepoint_name) if materialized?
|
375
|
+
connection.rollback_to_savepoint(savepoint_name) if materialized? && connection.active?
|
353
376
|
end
|
354
377
|
@state.rollback!
|
355
378
|
@instrumenter.finish(:rollback) if materialized?
|
@@ -532,9 +555,7 @@ module ActiveRecord
|
|
532
555
|
@connection.lock.synchronize do
|
533
556
|
transaction = begin_transaction(isolation: isolation, joinable: joinable)
|
534
557
|
begin
|
535
|
-
|
536
|
-
completed = true
|
537
|
-
ret
|
558
|
+
yield transaction
|
538
559
|
rescue Exception => error
|
539
560
|
rollback_transaction
|
540
561
|
after_failure_actions(transaction, error)
|
@@ -542,24 +563,8 @@ module ActiveRecord
|
|
542
563
|
raise
|
543
564
|
ensure
|
544
565
|
unless error
|
545
|
-
# In 7.1 we enforce timeout >= 0.4.0 which no longer use throw, so we can
|
546
|
-
# go back to the original behavior of committing on non-local return.
|
547
|
-
# If users are using throw, we assume it's not an error case.
|
548
|
-
completed = true if ActiveRecord.commit_transaction_on_non_local_return
|
549
|
-
|
550
566
|
if Thread.current.status == "aborting"
|
551
567
|
rollback_transaction
|
552
|
-
elsif !completed && transaction.written
|
553
|
-
ActiveRecord.deprecator.warn(<<~EOW)
|
554
|
-
A transaction is being rolled back because the transaction block was
|
555
|
-
exited using `return`, `break` or `throw`.
|
556
|
-
In Rails 7.2 this transaction will be committed instead.
|
557
|
-
To opt-in to the new behavior now and suppress this warning
|
558
|
-
you can set:
|
559
|
-
|
560
|
-
Rails.application.config.active_record.commit_transaction_on_non_local_return = true
|
561
|
-
EOW
|
562
|
-
rollback_transaction
|
563
568
|
else
|
564
569
|
begin
|
565
570
|
commit_transaction
|
@@ -590,7 +595,7 @@ module ActiveRecord
|
|
590
595
|
end
|
591
596
|
|
592
597
|
private
|
593
|
-
NULL_TRANSACTION = NullTransaction.new
|
598
|
+
NULL_TRANSACTION = NullTransaction.new.freeze
|
594
599
|
|
595
600
|
# Deallocate invalidated prepared statements outside of the transaction
|
596
601
|
def after_failure_actions(transaction, error)
|
@@ -23,7 +23,7 @@ module ActiveRecord
|
|
23
23
|
# and +:limit+ options, etc.
|
24
24
|
#
|
25
25
|
# All the concrete database adapters follow the interface laid down in this class.
|
26
|
-
# {ActiveRecord::Base.
|
26
|
+
# {ActiveRecord::Base.lease_connection}[rdoc-ref:ConnectionHandling#lease_connection] returns an AbstractAdapter object, which
|
27
27
|
# you can use.
|
28
28
|
#
|
29
29
|
# Most of the methods in the adapter are useful during migrations. Most
|
@@ -49,8 +49,6 @@ module ActiveRecord
|
|
49
49
|
return if value.eql?(@pool)
|
50
50
|
@schema_cache = nil
|
51
51
|
@pool = value
|
52
|
-
|
53
|
-
@pool.schema_reflection.load!(self) if ActiveRecord.lazily_load_schema_cache
|
54
52
|
end
|
55
53
|
|
56
54
|
set_callback :checkin, :after, :enable_lazy_transactions!
|
@@ -136,7 +134,7 @@ module ActiveRecord
|
|
136
134
|
@logger = ActiveRecord::Base.logger
|
137
135
|
|
138
136
|
if deprecated_logger || deprecated_connection_options || deprecated_config
|
139
|
-
raise ArgumentError, "when initializing an
|
137
|
+
raise ArgumentError, "when initializing an Active Record adapter with a config hash, that should be the only argument"
|
140
138
|
end
|
141
139
|
else
|
142
140
|
# Soft-deprecated for now; we'll probably warn in future.
|
@@ -174,19 +172,13 @@ module ActiveRecord
|
|
174
172
|
@verified = false
|
175
173
|
end
|
176
174
|
|
177
|
-
THREAD_LOCK = ActiveSupport::Concurrency::ThreadLoadInterlockAwareMonitor.new
|
178
|
-
private_constant :THREAD_LOCK
|
179
|
-
|
180
|
-
FIBER_LOCK = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
181
|
-
private_constant :FIBER_LOCK
|
182
|
-
|
183
175
|
def lock_thread=(lock_thread) # :nodoc:
|
184
176
|
@lock =
|
185
177
|
case lock_thread
|
186
178
|
when Thread
|
187
|
-
|
179
|
+
ActiveSupport::Concurrency::ThreadLoadInterlockAwareMonitor.new
|
188
180
|
when Fiber
|
189
|
-
|
181
|
+
ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
190
182
|
else
|
191
183
|
ActiveSupport::Concurrency::NullLock
|
192
184
|
end
|
@@ -215,10 +207,6 @@ module ActiveRecord
|
|
215
207
|
@config[:replica] || false
|
216
208
|
end
|
217
209
|
|
218
|
-
def use_metadata_table?
|
219
|
-
@config.fetch(:use_metadata_table, true)
|
220
|
-
end
|
221
|
-
|
222
210
|
def connection_retries
|
223
211
|
(@config[:connection_retries] || 1).to_i
|
224
212
|
end
|
@@ -246,22 +234,6 @@ module ActiveRecord
|
|
246
234
|
connection_class.current_preventing_writes
|
247
235
|
end
|
248
236
|
|
249
|
-
def migrations_paths # :nodoc:
|
250
|
-
@config[:migrations_paths] || Migrator.migrations_paths
|
251
|
-
end
|
252
|
-
|
253
|
-
def migration_context # :nodoc:
|
254
|
-
MigrationContext.new(migrations_paths, schema_migration, internal_metadata)
|
255
|
-
end
|
256
|
-
|
257
|
-
def schema_migration # :nodoc:
|
258
|
-
SchemaMigration.new(self)
|
259
|
-
end
|
260
|
-
|
261
|
-
def internal_metadata # :nodoc:
|
262
|
-
InternalMetadata.new(self)
|
263
|
-
end
|
264
|
-
|
265
237
|
def prepared_statements?
|
266
238
|
@prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
|
267
239
|
end
|
@@ -327,7 +299,7 @@ module ActiveRecord
|
|
327
299
|
end
|
328
300
|
|
329
301
|
def schema_cache
|
330
|
-
@schema_cache ||= BoundSchemaReflection.
|
302
|
+
@pool.schema_cache || (@schema_cache ||= BoundSchemaReflection.for_lone_connection(@pool.schema_reflection, self))
|
331
303
|
end
|
332
304
|
|
333
305
|
# this method must only be called while holding connection pool's mutex
|
@@ -580,7 +552,7 @@ module ActiveRecord
|
|
580
552
|
end
|
581
553
|
|
582
554
|
def return_value_after_insert?(column) # :nodoc:
|
583
|
-
column.
|
555
|
+
column.auto_populated?
|
584
556
|
end
|
585
557
|
|
586
558
|
def async_enabled? # :nodoc:
|
@@ -651,15 +623,6 @@ module ActiveRecord
|
|
651
623
|
yield
|
652
624
|
end
|
653
625
|
|
654
|
-
# Override to check all foreign key constraints in a database.
|
655
|
-
def all_foreign_keys_valid?
|
656
|
-
check_all_foreign_keys_valid!
|
657
|
-
true
|
658
|
-
rescue ActiveRecord::StatementInvalid
|
659
|
-
false
|
660
|
-
end
|
661
|
-
deprecate :all_foreign_keys_valid?, deprecator: ActiveRecord.deprecator
|
662
|
-
|
663
626
|
# Override to check all foreign key constraints in a database.
|
664
627
|
# The adapter should raise a +ActiveRecord::StatementInvalid+ if foreign key
|
665
628
|
# constraints are not met.
|
@@ -668,6 +631,13 @@ module ActiveRecord
|
|
668
631
|
|
669
632
|
# CONNECTION MANAGEMENT ====================================
|
670
633
|
|
634
|
+
# Checks whether the connection to the database was established. This doesn't
|
635
|
+
# include checking whether the database is actually capable of responding, i.e.
|
636
|
+
# whether the connection is stale.
|
637
|
+
def connected?
|
638
|
+
!@raw_connection.nil?
|
639
|
+
end
|
640
|
+
|
671
641
|
# Checks whether the connection to the database is still active. This includes
|
672
642
|
# checking whether the database is actually capable of responding, i.e. whether
|
673
643
|
# the connection isn't stale.
|
@@ -711,13 +681,14 @@ module ActiveRecord
|
|
711
681
|
end
|
712
682
|
end
|
713
683
|
|
714
|
-
|
715
684
|
# Disconnects from the database if already connected. Otherwise, this
|
716
685
|
# method does nothing.
|
717
686
|
def disconnect!
|
718
|
-
|
719
|
-
|
720
|
-
|
687
|
+
@lock.synchronize do
|
688
|
+
clear_cache!(new_connection: true)
|
689
|
+
reset_transaction
|
690
|
+
@raw_connection_dirty = false
|
691
|
+
end
|
721
692
|
end
|
722
693
|
|
723
694
|
# Immediately forget this connection ever existed. Unlike disconnect!,
|
@@ -773,19 +744,17 @@ module ActiveRecord
|
|
773
744
|
# is no longer active, then this method will reconnect to the database.
|
774
745
|
def verify!
|
775
746
|
unless active?
|
776
|
-
|
777
|
-
@
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
return
|
784
|
-
end
|
747
|
+
@lock.synchronize do
|
748
|
+
if @unconfigured_connection
|
749
|
+
@raw_connection = @unconfigured_connection
|
750
|
+
@unconfigured_connection = nil
|
751
|
+
configure_connection
|
752
|
+
@verified = true
|
753
|
+
return
|
785
754
|
end
|
786
|
-
end
|
787
755
|
|
788
|
-
|
756
|
+
reconnect!(restore_transactions: true)
|
757
|
+
end
|
789
758
|
end
|
790
759
|
|
791
760
|
@verified = true
|
@@ -868,7 +837,7 @@ module ActiveRecord
|
|
868
837
|
end
|
869
838
|
|
870
839
|
def database_version # :nodoc:
|
871
|
-
|
840
|
+
pool.server_version(self)
|
872
841
|
end
|
873
842
|
|
874
843
|
def check_version # :nodoc:
|
@@ -879,7 +848,7 @@ module ActiveRecord
|
|
879
848
|
# numbered migration that has been executed, or 0 if no schema
|
880
849
|
# information is present / the database is empty.
|
881
850
|
def schema_version
|
882
|
-
migration_context.current_version
|
851
|
+
pool.migration_context.current_version
|
883
852
|
end
|
884
853
|
|
885
854
|
class << self
|
@@ -1149,6 +1118,8 @@ module ActiveRecord
|
|
1149
1118
|
statement_name: statement_name,
|
1150
1119
|
async: async,
|
1151
1120
|
connection: self,
|
1121
|
+
transaction: current_transaction.presence,
|
1122
|
+
row_count: 0,
|
1152
1123
|
&block
|
1153
1124
|
)
|
1154
1125
|
rescue ActiveRecord::StatementInvalid => ex
|
@@ -1212,7 +1183,7 @@ module ActiveRecord
|
|
1212
1183
|
#
|
1213
1184
|
# This is an internal hook to make possible connection adapters to build
|
1214
1185
|
# custom result objects with connection-specific data.
|
1215
|
-
def build_result(columns:, rows:, column_types:
|
1186
|
+
def build_result(columns:, rows:, column_types: nil)
|
1216
1187
|
ActiveRecord::Result.new(columns, rows, column_types)
|
1217
1188
|
end
|
1218
1189
|
|
@@ -1224,6 +1195,7 @@ module ActiveRecord
|
|
1224
1195
|
# Implementations may assume this method will only be called while
|
1225
1196
|
# holding @lock (or from #initialize).
|
1226
1197
|
def configure_connection
|
1198
|
+
check_version
|
1227
1199
|
end
|
1228
1200
|
|
1229
1201
|
def default_prepared_statements
|
@@ -170,6 +170,10 @@ module ActiveRecord
|
|
170
170
|
true
|
171
171
|
end
|
172
172
|
|
173
|
+
def supports_insert_returning?
|
174
|
+
mariadb? && database_version >= "10.5.0"
|
175
|
+
end
|
176
|
+
|
173
177
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
174
178
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
175
179
|
end
|
@@ -214,7 +218,7 @@ module ActiveRecord
|
|
214
218
|
update("SET FOREIGN_KEY_CHECKS = 0")
|
215
219
|
yield
|
216
220
|
ensure
|
217
|
-
update("SET FOREIGN_KEY_CHECKS = #{old}")
|
221
|
+
update("SET FOREIGN_KEY_CHECKS = #{old}") if active?
|
218
222
|
end
|
219
223
|
end
|
220
224
|
|
@@ -225,12 +229,12 @@ module ActiveRecord
|
|
225
229
|
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
226
230
|
# to write stuff in an abstract way without concerning ourselves about whether it
|
227
231
|
# needs to be explicitly freed or not.
|
228
|
-
def execute_and_free(sql, name = nil, async: false) # :nodoc:
|
232
|
+
def execute_and_free(sql, name = nil, async: false, allow_retry: false) # :nodoc:
|
229
233
|
sql = transform_query(sql)
|
230
234
|
check_if_write_query(sql)
|
231
235
|
|
232
236
|
mark_transaction_written_if_write(sql)
|
233
|
-
yield raw_execute(sql, name, async: async)
|
237
|
+
yield raw_execute(sql, name, async: async, allow_retry: allow_retry)
|
234
238
|
end
|
235
239
|
|
236
240
|
def begin_db_transaction # :nodoc:
|
@@ -336,7 +340,7 @@ module ActiveRecord
|
|
336
340
|
schema_cache.clear_data_source_cache!(table_name.to_s)
|
337
341
|
schema_cache.clear_data_source_cache!(new_name.to_s)
|
338
342
|
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
339
|
-
rename_table_indexes(table_name, new_name)
|
343
|
+
rename_table_indexes(table_name, new_name, **options)
|
340
344
|
end
|
341
345
|
|
342
346
|
# Drops a table from the database.
|
@@ -635,27 +639,59 @@ module ActiveRecord
|
|
635
639
|
end
|
636
640
|
|
637
641
|
def build_insert_sql(insert) # :nodoc:
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
sql
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
642
|
+
no_op_column = quote_column_name(insert.keys.first)
|
643
|
+
|
644
|
+
# MySQL 8.0.19 replaces `VALUES(<expression>)` clauses with row and column alias names, see https://dev.mysql.com/worklog/task/?id=6312 .
|
645
|
+
# then MySQL 8.0.20 deprecates the `VALUES(<expression>)` see https://dev.mysql.com/worklog/task/?id=13325 .
|
646
|
+
if supports_insert_raw_alias_syntax?
|
647
|
+
values_alias = quote_table_name("#{insert.model.table_name}_values")
|
648
|
+
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"
|
649
|
+
|
650
|
+
if insert.skip_duplicates?
|
651
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{values_alias}.#{no_op_column}"
|
652
|
+
elsif insert.update_duplicates?
|
653
|
+
if insert.raw_update_sql?
|
654
|
+
sql = +"INSERT #{insert.into} #{insert.values_list} ON DUPLICATE KEY UPDATE #{insert.raw_update_sql}"
|
655
|
+
else
|
656
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
657
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column}<=>#{values_alias}.#{column}" }
|
658
|
+
sql << insert.updatable_columns.map { |column| "#{column}=#{values_alias}.#{column}" }.join(",")
|
659
|
+
end
|
660
|
+
end
|
661
|
+
else
|
662
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
663
|
+
|
664
|
+
if insert.skip_duplicates?
|
665
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
666
|
+
elsif insert.update_duplicates?
|
667
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
668
|
+
if insert.raw_update_sql?
|
669
|
+
sql << insert.raw_update_sql
|
670
|
+
else
|
671
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
|
672
|
+
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
673
|
+
end
|
650
674
|
end
|
651
675
|
end
|
652
676
|
|
677
|
+
sql << " RETURNING #{insert.returning}" if insert.returning
|
653
678
|
sql
|
654
679
|
end
|
655
680
|
|
656
681
|
def check_version # :nodoc:
|
657
682
|
if database_version < "5.5.8"
|
658
|
-
raise "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
|
683
|
+
raise DatabaseVersionError, "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
|
684
|
+
end
|
685
|
+
end
|
686
|
+
|
687
|
+
#--
|
688
|
+
# QUOTING ==================================================
|
689
|
+
#++
|
690
|
+
|
691
|
+
# Quotes strings for use in SQL input.
|
692
|
+
def quote_string(string)
|
693
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |connection|
|
694
|
+
connection.escape(string)
|
659
695
|
end
|
660
696
|
end
|
661
697
|
|
@@ -734,7 +770,11 @@ module ActiveRecord
|
|
734
770
|
return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
|
735
771
|
|
736
772
|
@affected_rows_before_warnings = @raw_connection.affected_rows
|
773
|
+
warning_count = @raw_connection.warning_count
|
737
774
|
result = @raw_connection.query("SHOW WARNINGS")
|
775
|
+
result = [
|
776
|
+
["Warning", nil, "Query had warning_count=#{warning_count} but ‘SHOW WARNINGS’ did not return the warnings. Check MySQL logs or database configuration."],
|
777
|
+
] if result.count == 0
|
738
778
|
result.each do |level, code, message|
|
739
779
|
warning = SQLWarning.new(message, code, level, sql, @pool)
|
740
780
|
next if warning_ignored?(warning)
|
@@ -756,6 +796,7 @@ module ActiveRecord
|
|
756
796
|
ER_DB_CREATE_EXISTS = 1007
|
757
797
|
ER_FILSORT_ABORT = 1028
|
758
798
|
ER_DUP_ENTRY = 1062
|
799
|
+
ER_SERVER_SHUTDOWN = 1053
|
759
800
|
ER_NOT_NULL_VIOLATION = 1048
|
760
801
|
ER_NO_REFERENCED_ROW = 1216
|
761
802
|
ER_ROW_IS_REFERENCED = 1217
|
@@ -784,7 +825,7 @@ module ActiveRecord
|
|
784
825
|
else
|
785
826
|
super
|
786
827
|
end
|
787
|
-
when ER_CONNECTION_KILLED, CR_SERVER_GONE_ERROR, CR_SERVER_LOST, ER_CLIENT_INTERACTION_TIMEOUT
|
828
|
+
when ER_CONNECTION_KILLED, ER_SERVER_SHUTDOWN, CR_SERVER_GONE_ERROR, CR_SERVER_LOST, ER_CLIENT_INTERACTION_TIMEOUT
|
788
829
|
ConnectionFailed.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
789
830
|
when ER_DB_CREATE_EXISTS
|
790
831
|
DatabaseAlreadyExists.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
@@ -853,6 +894,10 @@ module ActiveRecord
|
|
853
894
|
"DROP INDEX #{quote_column_name(index_name)}"
|
854
895
|
end
|
855
896
|
|
897
|
+
def supports_insert_raw_alias_syntax?
|
898
|
+
!mariadb? && database_version >= "8.0.19"
|
899
|
+
end
|
900
|
+
|
856
901
|
def supports_rename_index?
|
857
902
|
if mariadb?
|
858
903
|
database_version >= "10.5.2"
|
@@ -870,6 +915,7 @@ module ActiveRecord
|
|
870
915
|
end
|
871
916
|
|
872
917
|
def configure_connection
|
918
|
+
super
|
873
919
|
variables = @config.fetch(:variables, {}).stringify_keys
|
874
920
|
|
875
921
|
# Increase timeout so the server doesn't disconnect us.
|
@@ -977,7 +1023,11 @@ module ActiveRecord
|
|
977
1023
|
end
|
978
1024
|
|
979
1025
|
def version_string(full_version_string)
|
980
|
-
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)
|
1026
|
+
if full_version_string && matches = full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)
|
1027
|
+
matches[1]
|
1028
|
+
else
|
1029
|
+
raise DatabaseVersionError, "Unable to parse MySQL version from #{full_version_string.inspect}"
|
1030
|
+
end
|
981
1031
|
end
|
982
1032
|
end
|
983
1033
|
end
|
@@ -11,7 +11,7 @@ module ActiveRecord
|
|
11
11
|
|
12
12
|
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_current-timestamp
|
13
13
|
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-syntax.html
|
14
|
-
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP(6)").freeze # :nodoc:
|
14
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP(6)", retryable: true).freeze # :nodoc:
|
15
15
|
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
16
16
|
|
17
17
|
def write_query?(sql) # :nodoc:
|
@@ -55,6 +55,14 @@ module ActiveRecord
|
|
55
55
|
super unless column.auto_increment?
|
56
56
|
end
|
57
57
|
|
58
|
+
def returning_column_values(result)
|
59
|
+
if supports_insert_returning?
|
60
|
+
result.rows.first
|
61
|
+
else
|
62
|
+
super
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
58
66
|
def combine_multi_statements(total_sql)
|
59
67
|
total_sql.each_with_object([]) do |sql, total_sql_chunks|
|
60
68
|
previous_packet = total_sql_chunks.last
|