activerecord 7.1.5.2 → 8.1.2.1
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 +567 -2443
- data/README.rdoc +16 -16
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +3 -2
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +43 -12
- data/lib/active_record/associations/belongs_to_association.rb +31 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +18 -4
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- 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/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +36 -5
- 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 +268 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +4 -2
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +4 -3
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +8 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +14 -3
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +250 -315
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +25 -61
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +20 -27
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +19 -20
- data/lib/active_record/attribute_methods.rb +71 -75
- data/lib/active_record/attributes.rb +96 -68
- data/lib/active_record/autosave_association.rb +93 -58
- data/lib/active_record/base.rb +5 -7
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +50 -126
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +52 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +681 -135
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +165 -86
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +226 -78
- data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -114
- 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 +136 -34
- data/lib/active_record/connection_adapters/abstract/transaction.rb +163 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -129
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +112 -63
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -3
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
- 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 +79 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +97 -101
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +14 -33
- data/lib/active_record/connection_adapters/pool_config.rb +14 -13
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +98 -44
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- 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/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +79 -68
- 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 +44 -41
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +155 -75
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +104 -121
- data/lib/active_record/connection_adapters/schema_cache.rb +126 -133
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +91 -95
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +43 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -15
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +231 -111
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +40 -69
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
- data/lib/active_record/connection_adapters.rb +66 -0
- data/lib/active_record/connection_handling.rb +88 -46
- data/lib/active_record/core.rb +142 -58
- data/lib/active_record/counter_cache.rb +52 -18
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +28 -5
- data/lib/active_record/database_configurations/hash_config.rb +103 -41
- data/lib/active_record/database_configurations/url_config.rb +30 -1
- data/lib/active_record/database_configurations.rb +8 -4
- data/lib/active_record/delegated_type.rb +43 -19
- data/lib/active_record/dynamic_matchers.rb +56 -71
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +12 -12
- data/lib/active_record/encryption/encrypted_attribute_type.rb +35 -6
- data/lib/active_record/encryption/encryptor.rb +58 -22
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/key_provider.rb +1 -1
- 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 +9 -2
- data/lib/active_record/enum.rb +57 -36
- data/lib/active_record/errors.rb +76 -26
- data/lib/active_record/explain.rb +14 -25
- 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 +39 -35
- data/lib/active_record/future_result.rb +21 -13
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +5 -3
- data/lib/active_record/insert_all.rb +28 -20
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +15 -7
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +3 -34
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +46 -14
- data/lib/active_record/migration/compatibility.rb +40 -25
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- 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 +119 -103
- data/lib/active_record/model_schema.rb +66 -78
- data/lib/active_record/nested_attributes.rb +17 -9
- data/lib/active_record/persistence.rb +161 -454
- data/lib/active_record/query_cache.rb +33 -15
- data/lib/active_record/query_logs.rb +106 -39
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +28 -16
- data/lib/active_record/railtie.rb +61 -74
- data/lib/active_record/railties/controller_runtime.rb +19 -5
- data/lib/active_record/railties/databases.rake +64 -78
- 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 +147 -53
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +153 -73
- data/lib/active_record/relation/calculations.rb +146 -96
- data/lib/active_record/relation/delegation.rb +30 -23
- data/lib/active_record/relation/finder_methods.rb +64 -34
- data/lib/active_record/relation/merger.rb +12 -14
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +19 -11
- 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 +25 -10
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +351 -124
- data/lib/active_record/relation/spawn_methods.rb +9 -25
- data/lib/active_record/relation/where_clause.rb +17 -30
- data/lib/active_record/relation.rb +590 -124
- data/lib/active_record/result.rb +131 -59
- data/lib/active_record/runtime_registry.rb +44 -21
- data/lib/active_record/sanitization.rb +33 -25
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +66 -31
- data/lib/active_record/schema_migration.rb +31 -14
- data/lib/active_record/scoping/named.rb +6 -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 +68 -20
- data/lib/active_record/statement_cache.rb +29 -25
- 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 +7 -33
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +118 -90
- 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 +17 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +123 -89
- data/lib/active_record/testing/query_assertions.rb +127 -0
- data/lib/active_record/timestamp.rb +6 -4
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +129 -0
- data/lib/active_record/transactions.rb +97 -18
- data/lib/active_record/translation.rb +0 -2
- 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 +12 -7
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +5 -4
- data/lib/active_record/validations/associated.rb +10 -4
- data/lib/active_record/validations/uniqueness.rb +23 -18
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +203 -59
- data/lib/arel/alias_predication.rb +3 -1
- data/lib/arel/collectors/bind.rb +4 -2
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +2 -2
- data/lib/arel/collectors/substitute_binds.rb +3 -3
- data/lib/arel/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -7
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- 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/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +6 -5
- data/lib/arel/nodes/sql_literal.rb +8 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +2 -4
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +14 -5
- data/lib/arel/table.rb +3 -7
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -3
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +56 -12
- data/lib/arel/visitors/sqlite.rb +80 -8
- data/lib/arel/visitors/to_sql.rb +34 -37
- data/lib/arel.rb +10 -4
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +23 -14
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -167
- data/lib/active_record/relation/record_fetch_warning.rb +0 -49
|
@@ -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
|
|
@@ -89,7 +91,9 @@ module ActiveRecord
|
|
|
89
91
|
raise InstrumentationAlreadyStartedError.new("Called start on an already started transaction") if @started
|
|
90
92
|
@started = true
|
|
91
93
|
|
|
92
|
-
|
|
94
|
+
ActiveSupport::Notifications.instrument("start_transaction.active_record", @base_payload)
|
|
95
|
+
|
|
96
|
+
@payload = @base_payload.dup # We dup because the payload for a given event is mutated later to add the outcome.
|
|
93
97
|
@handle = ActiveSupport::Notifications.instrumenter.build_handle("transaction.active_record", @payload)
|
|
94
98
|
@handle.start
|
|
95
99
|
end
|
|
@@ -104,28 +108,64 @@ module ActiveRecord
|
|
|
104
108
|
end
|
|
105
109
|
|
|
106
110
|
class NullTransaction # :nodoc:
|
|
107
|
-
def initialize; end
|
|
108
111
|
def state; end
|
|
109
112
|
def closed?; true; end
|
|
110
113
|
def open?; false; end
|
|
111
114
|
def joinable?; false; end
|
|
115
|
+
def isolation; nil; end
|
|
112
116
|
def add_record(record, _ = true); end
|
|
113
117
|
def restartable?; false; end
|
|
114
118
|
def dirty?; false; end
|
|
115
119
|
def dirty!; end
|
|
116
120
|
def invalidated?; false; end
|
|
117
121
|
def invalidate!; end
|
|
122
|
+
def materialized?; false; end
|
|
123
|
+
def before_commit; yield; end
|
|
124
|
+
def after_commit; yield; end
|
|
125
|
+
def after_rollback; end
|
|
126
|
+
def user_transaction; ActiveRecord::Transaction::NULL_TRANSACTION; end
|
|
127
|
+
def isolation=(_); end
|
|
118
128
|
end
|
|
119
129
|
|
|
120
130
|
class Transaction # :nodoc:
|
|
121
|
-
|
|
131
|
+
class Callback # :nodoc:
|
|
132
|
+
def initialize(event, callback)
|
|
133
|
+
@event = event
|
|
134
|
+
@callback = callback
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def before_commit
|
|
138
|
+
@callback.call if @event == :before_commit
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def after_commit
|
|
142
|
+
@callback.call if @event == :after_commit
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def after_rollback
|
|
146
|
+
@callback.call if @event == :after_rollback
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
attr_reader :connection, :state, :savepoint_name, :isolation_level, :user_transaction
|
|
122
151
|
attr_accessor :written
|
|
123
152
|
|
|
124
153
|
delegate :invalidate!, :invalidated?, to: :@state
|
|
125
154
|
|
|
155
|
+
# Returns the isolation level if it was explicitly set, nil otherwise
|
|
156
|
+
def isolation
|
|
157
|
+
@isolation_level
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def isolation=(isolation) # :nodoc:
|
|
161
|
+
@isolation_level = isolation
|
|
162
|
+
end
|
|
163
|
+
|
|
126
164
|
def initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false)
|
|
165
|
+
super()
|
|
127
166
|
@connection = connection
|
|
128
167
|
@state = TransactionState.new
|
|
168
|
+
@callbacks = nil
|
|
129
169
|
@records = nil
|
|
130
170
|
@isolation_level = isolation
|
|
131
171
|
@materialized = false
|
|
@@ -133,7 +173,8 @@ module ActiveRecord
|
|
|
133
173
|
@run_commit_callbacks = run_commit_callbacks
|
|
134
174
|
@lazy_enrollment_records = nil
|
|
135
175
|
@dirty = false
|
|
136
|
-
@
|
|
176
|
+
@user_transaction = joinable ? ActiveRecord::Transaction.new(self) : ActiveRecord::Transaction::NULL_TRANSACTION
|
|
177
|
+
@instrumenter = TransactionInstrumenter.new(connection: connection, transaction: @user_transaction)
|
|
137
178
|
end
|
|
138
179
|
|
|
139
180
|
def dirty!
|
|
@@ -144,6 +185,14 @@ module ActiveRecord
|
|
|
144
185
|
@dirty
|
|
145
186
|
end
|
|
146
187
|
|
|
188
|
+
def open?
|
|
189
|
+
!closed?
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def closed?
|
|
193
|
+
@state.finalized?
|
|
194
|
+
end
|
|
195
|
+
|
|
147
196
|
def add_record(record, ensure_finalize = true)
|
|
148
197
|
@records ||= []
|
|
149
198
|
if ensure_finalize
|
|
@@ -154,6 +203,30 @@ module ActiveRecord
|
|
|
154
203
|
end
|
|
155
204
|
end
|
|
156
205
|
|
|
206
|
+
def before_commit(&block)
|
|
207
|
+
if @state.finalized?
|
|
208
|
+
raise ActiveRecordError, "Cannot register callbacks on a finalized transaction"
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
(@callbacks ||= []) << Callback.new(:before_commit, block)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def after_commit(&block)
|
|
215
|
+
if @state.finalized?
|
|
216
|
+
raise ActiveRecordError, "Cannot register callbacks on a finalized transaction"
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
(@callbacks ||= []) << Callback.new(:after_commit, block)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def after_rollback(&block)
|
|
223
|
+
if @state.finalized?
|
|
224
|
+
raise ActiveRecordError, "Cannot register callbacks on a finalized transaction"
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
(@callbacks ||= []) << Callback.new(:after_rollback, block)
|
|
228
|
+
end
|
|
229
|
+
|
|
157
230
|
def records
|
|
158
231
|
if @lazy_enrollment_records
|
|
159
232
|
@records.concat @lazy_enrollment_records.values
|
|
@@ -190,66 +263,85 @@ module ActiveRecord
|
|
|
190
263
|
end
|
|
191
264
|
|
|
192
265
|
def rollback_records
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
266
|
+
if records
|
|
267
|
+
begin
|
|
268
|
+
ite = unique_records
|
|
196
269
|
|
|
197
|
-
|
|
270
|
+
instances_to_run_callbacks_on = prepare_instances_to_run_callbacks_on(ite)
|
|
198
271
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
272
|
+
run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks|
|
|
273
|
+
record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks)
|
|
274
|
+
end
|
|
275
|
+
ensure
|
|
276
|
+
ite&.each do |i|
|
|
277
|
+
i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
|
|
278
|
+
end
|
|
279
|
+
end
|
|
205
280
|
end
|
|
281
|
+
|
|
282
|
+
@callbacks&.each(&:after_rollback)
|
|
206
283
|
end
|
|
207
284
|
|
|
208
285
|
def before_commit_records
|
|
209
|
-
return unless records
|
|
210
|
-
|
|
211
286
|
if @run_commit_callbacks
|
|
212
|
-
if
|
|
213
|
-
|
|
287
|
+
if records
|
|
288
|
+
if ActiveRecord.before_committed_on_all_records
|
|
289
|
+
ite = unique_records
|
|
214
290
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
291
|
+
instances_to_run_callbacks_on = records.each_with_object({}) do |record, candidates|
|
|
292
|
+
candidates[record] = record
|
|
293
|
+
end
|
|
218
294
|
|
|
219
|
-
|
|
220
|
-
|
|
295
|
+
run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks|
|
|
296
|
+
record.before_committed! if should_run_callbacks
|
|
297
|
+
end
|
|
298
|
+
else
|
|
299
|
+
records.uniq.each(&:before_committed!)
|
|
221
300
|
end
|
|
222
|
-
else
|
|
223
|
-
records.uniq.each(&:before_committed!)
|
|
224
301
|
end
|
|
302
|
+
|
|
303
|
+
@callbacks&.each(&:before_commit)
|
|
225
304
|
end
|
|
305
|
+
# Note: When @run_commit_callbacks is false #commit_records takes care of appending
|
|
306
|
+
# remaining callbacks to the parent transaction
|
|
226
307
|
end
|
|
227
308
|
|
|
228
309
|
def commit_records
|
|
229
|
-
|
|
310
|
+
if records
|
|
311
|
+
begin
|
|
312
|
+
ite = unique_records
|
|
230
313
|
|
|
231
|
-
|
|
314
|
+
if @run_commit_callbacks
|
|
315
|
+
instances_to_run_callbacks_on = prepare_instances_to_run_callbacks_on(ite)
|
|
232
316
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
317
|
+
run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks|
|
|
318
|
+
record.committed!(should_run_callbacks: should_run_callbacks)
|
|
319
|
+
end
|
|
320
|
+
else
|
|
321
|
+
while record = ite.shift
|
|
322
|
+
# if not running callbacks, only adds the record to the parent transaction
|
|
323
|
+
connection.add_transaction_record(record)
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
ensure
|
|
327
|
+
ite&.each { |i| i.committed!(should_run_callbacks: false) }
|
|
243
328
|
end
|
|
244
329
|
end
|
|
245
|
-
|
|
246
|
-
|
|
330
|
+
|
|
331
|
+
if @run_commit_callbacks
|
|
332
|
+
@callbacks&.each(&:after_commit)
|
|
333
|
+
elsif @callbacks
|
|
334
|
+
connection.current_transaction.append_callbacks(@callbacks)
|
|
335
|
+
end
|
|
247
336
|
end
|
|
248
337
|
|
|
249
338
|
def full_rollback?; true; end
|
|
250
339
|
def joinable?; @joinable; end
|
|
251
|
-
|
|
252
|
-
|
|
340
|
+
|
|
341
|
+
protected
|
|
342
|
+
def append_callbacks(callbacks) # :nodoc:
|
|
343
|
+
(@callbacks ||= []).concat(callbacks)
|
|
344
|
+
end
|
|
253
345
|
|
|
254
346
|
private
|
|
255
347
|
def unique_records
|
|
@@ -305,7 +397,7 @@ module ActiveRecord
|
|
|
305
397
|
@parent.state.add_child(@state)
|
|
306
398
|
end
|
|
307
399
|
|
|
308
|
-
delegate :materialize!, :materialized?, :restart, to: :@parent
|
|
400
|
+
delegate :materialize!, :materialized?, :restart, :isolation, to: :@parent
|
|
309
401
|
|
|
310
402
|
def rollback
|
|
311
403
|
@state.rollback!
|
|
@@ -324,6 +416,7 @@ module ActiveRecord
|
|
|
324
416
|
def initialize(connection, savepoint_name, parent_transaction, **options)
|
|
325
417
|
super(connection, **options)
|
|
326
418
|
|
|
419
|
+
@parent_transaction = parent_transaction
|
|
327
420
|
parent_transaction.state.add_child(@state)
|
|
328
421
|
|
|
329
422
|
if isolation_level
|
|
@@ -333,6 +426,15 @@ module ActiveRecord
|
|
|
333
426
|
@savepoint_name = savepoint_name
|
|
334
427
|
end
|
|
335
428
|
|
|
429
|
+
# Delegates to parent transaction's isolation level
|
|
430
|
+
def isolation
|
|
431
|
+
@parent_transaction.isolation
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def isolation=(isolation) # :nodoc:
|
|
435
|
+
@parent_transaction.isolation = isolation
|
|
436
|
+
end
|
|
437
|
+
|
|
336
438
|
def materialize!
|
|
337
439
|
connection.create_savepoint(savepoint_name)
|
|
338
440
|
super
|
|
@@ -349,7 +451,7 @@ module ActiveRecord
|
|
|
349
451
|
|
|
350
452
|
def rollback
|
|
351
453
|
unless @state.invalidated?
|
|
352
|
-
connection.rollback_to_savepoint(savepoint_name) if materialized?
|
|
454
|
+
connection.rollback_to_savepoint(savepoint_name) if materialized? && connection.active?
|
|
353
455
|
end
|
|
354
456
|
@state.rollback!
|
|
355
457
|
@instrumenter.finish(:rollback) if materialized?
|
|
@@ -367,10 +469,14 @@ module ActiveRecord
|
|
|
367
469
|
# = Active Record Real \Transaction
|
|
368
470
|
class RealTransaction < Transaction
|
|
369
471
|
def materialize!
|
|
370
|
-
if
|
|
371
|
-
|
|
472
|
+
if joinable?
|
|
473
|
+
if isolation_level
|
|
474
|
+
connection.begin_isolated_db_transaction(isolation_level)
|
|
475
|
+
else
|
|
476
|
+
connection.begin_db_transaction
|
|
477
|
+
end
|
|
372
478
|
else
|
|
373
|
-
connection.
|
|
479
|
+
connection.begin_deferred_transaction(isolation_level)
|
|
374
480
|
end
|
|
375
481
|
|
|
376
482
|
super
|
|
@@ -391,13 +497,19 @@ module ActiveRecord
|
|
|
391
497
|
end
|
|
392
498
|
|
|
393
499
|
def rollback
|
|
394
|
-
|
|
500
|
+
if materialized?
|
|
501
|
+
connection.rollback_db_transaction
|
|
502
|
+
connection.reset_isolation_level if isolation_level
|
|
503
|
+
end
|
|
395
504
|
@state.full_rollback!
|
|
396
505
|
@instrumenter.finish(:rollback) if materialized?
|
|
397
506
|
end
|
|
398
507
|
|
|
399
508
|
def commit
|
|
400
|
-
|
|
509
|
+
if materialized?
|
|
510
|
+
connection.commit_db_transaction
|
|
511
|
+
connection.reset_isolation_level if isolation_level
|
|
512
|
+
end
|
|
401
513
|
@state.full_commit!
|
|
402
514
|
@instrumenter.finish(:commit) if materialized?
|
|
403
515
|
end
|
|
@@ -529,12 +641,11 @@ module ActiveRecord
|
|
|
529
641
|
end
|
|
530
642
|
|
|
531
643
|
def within_new_transaction(isolation: nil, joinable: true)
|
|
644
|
+
isolation ||= @connection.pool.pool_transaction_isolation_level
|
|
532
645
|
@connection.lock.synchronize do
|
|
533
646
|
transaction = begin_transaction(isolation: isolation, joinable: joinable)
|
|
534
647
|
begin
|
|
535
|
-
|
|
536
|
-
completed = true
|
|
537
|
-
ret
|
|
648
|
+
yield transaction.user_transaction
|
|
538
649
|
rescue Exception => error
|
|
539
650
|
rollback_transaction
|
|
540
651
|
after_failure_actions(transaction, error)
|
|
@@ -542,24 +653,8 @@ module ActiveRecord
|
|
|
542
653
|
raise
|
|
543
654
|
ensure
|
|
544
655
|
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
656
|
if Thread.current.status == "aborting"
|
|
551
657
|
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
658
|
else
|
|
564
659
|
begin
|
|
565
660
|
commit_transaction
|
|
@@ -590,7 +685,7 @@ module ActiveRecord
|
|
|
590
685
|
end
|
|
591
686
|
|
|
592
687
|
private
|
|
593
|
-
NULL_TRANSACTION = NullTransaction.new
|
|
688
|
+
NULL_TRANSACTION = NullTransaction.new.freeze
|
|
594
689
|
|
|
595
690
|
# Deallocate invalidated prepared statements outside of the transaction
|
|
596
691
|
def after_failure_actions(transaction, error)
|