activerecord 7.1.5.1 → 8.0.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 +369 -2484
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +2 -1
- 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 +21 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +7 -6
- 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 +17 -9
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +265 -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/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +4 -3
- 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 +14 -3
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +92 -295
- 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/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +4 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -18
- data/lib/active_record/attribute_methods.rb +71 -75
- data/lib/active_record/attributes.rb +63 -49
- data/lib/active_record/autosave_association.rb +92 -57
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +48 -122
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +286 -77
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +119 -55
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +197 -76
- data/lib/active_record/connection_adapters/abstract/quoting.rb +66 -92
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +12 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -12
- data/lib/active_record/connection_adapters/abstract/transaction.rb +140 -67
- data/lib/active_record/connection_adapters/abstract_adapter.rb +85 -90
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +71 -52
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +56 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +92 -101
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +13 -31
- data/lib/active_record/connection_adapters/pool_config.rb +14 -13
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -41
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- 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/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +36 -20
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +75 -28
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +73 -113
- data/lib/active_record/connection_adapters/schema_cache.rb +124 -131
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +81 -97
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -46
- 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 +29 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +35 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +183 -87
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +39 -69
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
- data/lib/active_record/connection_adapters.rb +65 -0
- data/lib/active_record/connection_handling.rb +74 -37
- data/lib/active_record/core.rb +132 -51
- data/lib/active_record/counter_cache.rb +19 -10
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +23 -4
- data/lib/active_record/database_configurations/hash_config.rb +46 -34
- 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 +41 -17
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +7 -7
- data/lib/active_record/encryption/encrypted_attribute_type.rb +33 -4
- data/lib/active_record/encryption/encryptor.rb +28 -6
- 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 +8 -1
- data/lib/active_record/enum.rb +20 -16
- data/lib/active_record/errors.rb +54 -20
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -33
- data/lib/active_record/future_result.rb +21 -13
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +19 -16
- 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 +5 -32
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +33 -14
- data/lib/active_record/migration/compatibility.rb +8 -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 +104 -98
- data/lib/active_record/model_schema.rb +32 -70
- data/lib/active_record/nested_attributes.rb +15 -9
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +127 -451
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +104 -37
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +24 -12
- data/lib/active_record/railtie.rb +26 -68
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +43 -61
- data/lib/active_record/reflection.rb +112 -53
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +138 -72
- data/lib/active_record/relation/calculations.rb +122 -82
- data/lib/active_record/relation/delegation.rb +30 -22
- data/lib/active_record/relation/finder_methods.rb +32 -18
- 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 +10 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +16 -3
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +317 -101
- data/lib/active_record/relation/spawn_methods.rb +3 -19
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +561 -119
- data/lib/active_record/result.rb +95 -46
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +31 -25
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +53 -20
- data/lib/active_record/schema_migration.rb +31 -14
- data/lib/active_record/scoping/named.rb +6 -2
- data/lib/active_record/signed_id.rb +24 -4
- data/lib/active_record/statement_cache.rb +19 -19
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/table_metadata.rb +2 -13
- data/lib/active_record/tasks/database_tasks.rb +87 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -3
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +4 -3
- data/lib/active_record/test_fixtures.rb +98 -89
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +2 -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 +132 -0
- data/lib/active_record/transactions.rb +72 -17
- 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 +23 -18
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +138 -57
- data/lib/arel/alias_predication.rb +1 -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/nodes/binary.rb +1 -7
- 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 +5 -4
- data/lib/arel/nodes/sql_literal.rb +8 -1
- 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/table.rb +3 -7
- data/lib/arel/tree_manager.rb +3 -2
- 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/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +29 -16
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +18 -16
- data/lib/active_record/relation/record_fetch_warning.rb +0 -49
@@ -14,7 +14,7 @@ module ActiveRecord
|
|
14
14
|
sql
|
15
15
|
end
|
16
16
|
|
17
|
-
def to_sql_and_binds(arel_or_sql_string, binds = [], preparable = nil) # :nodoc:
|
17
|
+
def to_sql_and_binds(arel_or_sql_string, binds = [], preparable = nil, allow_retry = false) # :nodoc:
|
18
18
|
# Arel::TreeManager -> Arel::Node
|
19
19
|
if arel_or_sql_string.respond_to?(:ast)
|
20
20
|
arel_or_sql_string = arel_or_sql_string.ast
|
@@ -27,6 +27,7 @@ module ActiveRecord
|
|
27
27
|
end
|
28
28
|
|
29
29
|
collector = collector()
|
30
|
+
collector.retryable = true
|
30
31
|
|
31
32
|
if prepared_statements
|
32
33
|
collector.preparable = true
|
@@ -41,10 +42,11 @@ module ActiveRecord
|
|
41
42
|
else
|
42
43
|
sql = visitor.compile(arel_or_sql_string, collector)
|
43
44
|
end
|
44
|
-
|
45
|
+
allow_retry = collector.retryable
|
46
|
+
[sql.freeze, binds, preparable, allow_retry]
|
45
47
|
else
|
46
48
|
arel_or_sql_string = arel_or_sql_string.dup.freeze unless arel_or_sql_string.frozen?
|
47
|
-
[arel_or_sql_string, binds, preparable]
|
49
|
+
[arel_or_sql_string, binds, preparable, allow_retry]
|
48
50
|
end
|
49
51
|
end
|
50
52
|
private :to_sql_and_binds
|
@@ -64,11 +66,15 @@ module ActiveRecord
|
|
64
66
|
end
|
65
67
|
|
66
68
|
# Returns an ActiveRecord::Result instance.
|
67
|
-
def select_all(arel, name = nil, binds = [], preparable: nil, async: false)
|
69
|
+
def select_all(arel, name = nil, binds = [], preparable: nil, async: false, allow_retry: false)
|
68
70
|
arel = arel_from_relation(arel)
|
69
|
-
sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
|
71
|
+
sql, binds, preparable, allow_retry = to_sql_and_binds(arel, binds, preparable, allow_retry)
|
70
72
|
|
71
|
-
select(sql, name, binds,
|
73
|
+
select(sql, name, binds,
|
74
|
+
prepare: prepared_statements && preparable,
|
75
|
+
async: async && FutureResult::SelectAll,
|
76
|
+
allow_retry: allow_retry
|
77
|
+
)
|
72
78
|
rescue ::RangeError
|
73
79
|
ActiveRecord::Result.empty(async: async)
|
74
80
|
end
|
@@ -96,16 +102,16 @@ module ActiveRecord
|
|
96
102
|
select_all(arel, name, binds, async: async).then(&:rows)
|
97
103
|
end
|
98
104
|
|
99
|
-
def query_value(
|
100
|
-
single_value_from_rows(query(
|
105
|
+
def query_value(...) # :nodoc:
|
106
|
+
single_value_from_rows(query(...))
|
101
107
|
end
|
102
108
|
|
103
|
-
def query_values(
|
104
|
-
query(
|
109
|
+
def query_values(...) # :nodoc:
|
110
|
+
query(...).map(&:first)
|
105
111
|
end
|
106
112
|
|
107
|
-
def query(
|
108
|
-
internal_exec_query(
|
113
|
+
def query(...) # :nodoc:
|
114
|
+
internal_exec_query(...).rows
|
109
115
|
end
|
110
116
|
|
111
117
|
# Determines whether the SQL statement is a write query.
|
@@ -157,14 +163,14 @@ module ActiveRecord
|
|
157
163
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
158
164
|
# the executed +sql+ statement.
|
159
165
|
def exec_delete(sql, name = nil, binds = [])
|
160
|
-
|
166
|
+
affected_rows(internal_execute(sql, name, binds))
|
161
167
|
end
|
162
168
|
|
163
169
|
# Executes update +sql+ statement in the context of this connection using
|
164
170
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
165
171
|
# the executed +sql+ statement.
|
166
172
|
def exec_update(sql, name = nil, binds = [])
|
167
|
-
|
173
|
+
affected_rows(internal_execute(sql, name, binds))
|
168
174
|
end
|
169
175
|
|
170
176
|
def exec_insert_all(sql, name) # :nodoc:
|
@@ -214,21 +220,30 @@ module ActiveRecord
|
|
214
220
|
end
|
215
221
|
|
216
222
|
def truncate_tables(*table_names) # :nodoc:
|
217
|
-
table_names -= [schema_migration.table_name, internal_metadata.table_name]
|
223
|
+
table_names -= [pool.schema_migration.table_name, pool.internal_metadata.table_name]
|
218
224
|
|
219
225
|
return if table_names.empty?
|
220
226
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
execute_batch(statements, "Truncate Tables")
|
225
|
-
end
|
227
|
+
disable_referential_integrity do
|
228
|
+
statements = build_truncate_statements(table_names)
|
229
|
+
execute_batch(statements, "Truncate Tables")
|
226
230
|
end
|
227
231
|
end
|
228
232
|
|
229
233
|
# Runs the given block in a database transaction, and returns the result
|
230
234
|
# of the block.
|
231
235
|
#
|
236
|
+
# == Transaction callbacks
|
237
|
+
#
|
238
|
+
# #transaction yields an ActiveRecord::Transaction object on which it is
|
239
|
+
# possible to register callback:
|
240
|
+
#
|
241
|
+
# ActiveRecord::Base.transaction do |transaction|
|
242
|
+
# transaction.before_commit { puts "before commit!" }
|
243
|
+
# transaction.after_commit { puts "after commit!" }
|
244
|
+
# transaction.after_rollback { puts "after rollback!" }
|
245
|
+
# end
|
246
|
+
#
|
232
247
|
# == Nested transactions support
|
233
248
|
#
|
234
249
|
# #transaction calls can be nested. By default, this makes all database
|
@@ -296,9 +311,9 @@ module ActiveRecord
|
|
296
311
|
# #transaction will raise exceptions when it tries to release the
|
297
312
|
# already-automatically-released savepoints:
|
298
313
|
#
|
299
|
-
# Model.
|
300
|
-
# Model.
|
301
|
-
# Model.
|
314
|
+
# Model.lease_connection.transaction do # BEGIN
|
315
|
+
# Model.lease_connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
|
316
|
+
# Model.lease_connection.create_table(...)
|
302
317
|
# # active_record_1 now automatically released
|
303
318
|
# end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
|
304
319
|
# end
|
@@ -339,9 +354,9 @@ module ActiveRecord
|
|
339
354
|
if isolation
|
340
355
|
raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
|
341
356
|
end
|
342
|
-
yield
|
357
|
+
yield current_transaction.user_transaction
|
343
358
|
else
|
344
|
-
|
359
|
+
within_new_transaction(isolation: isolation, joinable: joinable, &block)
|
345
360
|
end
|
346
361
|
rescue ActiveRecord::Rollback
|
347
362
|
# rollbacks are silently swallowed
|
@@ -394,6 +409,14 @@ module ActiveRecord
|
|
394
409
|
# Begins the transaction (and turns off auto-committing).
|
395
410
|
def begin_db_transaction() end
|
396
411
|
|
412
|
+
def begin_deferred_transaction(isolation_level = nil) # :nodoc:
|
413
|
+
if isolation_level
|
414
|
+
begin_isolated_db_transaction(isolation_level)
|
415
|
+
else
|
416
|
+
begin_db_transaction
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
397
420
|
def transaction_isolation_levels
|
398
421
|
{
|
399
422
|
read_uncommitted: "READ UNCOMMITTED",
|
@@ -410,6 +433,15 @@ module ActiveRecord
|
|
410
433
|
raise ActiveRecord::TransactionIsolationError, "adapter does not support setting transaction isolation"
|
411
434
|
end
|
412
435
|
|
436
|
+
# Hook point called after an isolated DB transaction is committed
|
437
|
+
# or rolled back.
|
438
|
+
# Most adapters don't need to implement anything because the isolation
|
439
|
+
# level is set on a per transaction basis.
|
440
|
+
# But some databases like SQLite set it on a per connection level
|
441
|
+
# and need to explicitly reset it after commit or rollback.
|
442
|
+
def reset_isolation_level
|
443
|
+
end
|
444
|
+
|
413
445
|
# Commits the transaction (and turns on auto-committing).
|
414
446
|
def commit_db_transaction() end
|
415
447
|
|
@@ -456,11 +488,9 @@ module ActiveRecord
|
|
456
488
|
table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" }
|
457
489
|
statements = table_deletes + fixture_inserts
|
458
490
|
|
459
|
-
|
491
|
+
transaction(requires_new: true) do
|
460
492
|
disable_referential_integrity do
|
461
|
-
|
462
|
-
execute_batch(statements, "Fixtures Load")
|
463
|
-
end
|
493
|
+
execute_batch(statements, "Fixtures Load")
|
464
494
|
end
|
465
495
|
end
|
466
496
|
end
|
@@ -495,7 +525,7 @@ module ActiveRecord
|
|
495
525
|
end
|
496
526
|
|
497
527
|
# This is a safe default, even if not high precision on all databases
|
498
|
-
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP").freeze # :nodoc:
|
528
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP", retryable: true).freeze # :nodoc:
|
499
529
|
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
500
530
|
|
501
531
|
# Returns an Arel SQL literal for the CURRENT_TIMESTAMP for usage with
|
@@ -507,28 +537,64 @@ module ActiveRecord
|
|
507
537
|
HIGH_PRECISION_CURRENT_TIMESTAMP
|
508
538
|
end
|
509
539
|
|
510
|
-
|
511
|
-
|
540
|
+
# Same as raw_execute but returns an ActiveRecord::Result object.
|
541
|
+
def raw_exec_query(...) # :nodoc:
|
542
|
+
cast_result(raw_execute(...))
|
543
|
+
end
|
544
|
+
|
545
|
+
# Execute a query and returns an ActiveRecord::Result
|
546
|
+
def internal_exec_query(...) # :nodoc:
|
547
|
+
cast_result(internal_execute(...))
|
512
548
|
end
|
513
549
|
|
514
550
|
private
|
515
|
-
|
516
|
-
|
517
|
-
|
551
|
+
# Lowest level way to execute a query. Doesn't check for illegal writes, doesn't annotate queries, yields a native result object.
|
552
|
+
def raw_execute(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true, batch: false)
|
553
|
+
type_casted_binds = type_casted_binds(binds)
|
554
|
+
log(sql, name, binds, type_casted_binds, async: async) do |notification_payload|
|
555
|
+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
556
|
+
perform_query(conn, sql, binds, type_casted_binds, prepare: prepare, notification_payload: notification_payload, batch: batch)
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end
|
518
560
|
|
519
|
-
|
561
|
+
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch:)
|
562
|
+
raise NotImplementedError
|
563
|
+
end
|
520
564
|
|
521
|
-
|
565
|
+
# Receive a native adapter result object and returns an ActiveRecord::Result object.
|
566
|
+
def cast_result(raw_result)
|
567
|
+
raise NotImplementedError
|
522
568
|
end
|
523
569
|
|
524
|
-
def
|
525
|
-
|
526
|
-
|
570
|
+
def affected_rows(raw_result)
|
571
|
+
raise NotImplementedError
|
572
|
+
end
|
573
|
+
|
574
|
+
def preprocess_query(sql)
|
575
|
+
check_if_write_query(sql)
|
576
|
+
mark_transaction_written_if_write(sql)
|
577
|
+
|
578
|
+
# We call tranformers after the write checks so we don't add extra parsing work.
|
579
|
+
# This means we assume no transformer whille change a read for a write
|
580
|
+
# but it would be insane to do such a thing.
|
581
|
+
ActiveRecord.query_transformers.each do |transformer|
|
582
|
+
sql = transformer.call(sql, self)
|
527
583
|
end
|
584
|
+
|
585
|
+
sql
|
528
586
|
end
|
529
587
|
|
530
|
-
|
531
|
-
|
588
|
+
# Same as #internal_exec_query, but yields a native adapter result
|
589
|
+
def internal_execute(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true, &block)
|
590
|
+
sql = preprocess_query(sql)
|
591
|
+
raw_execute(sql, name, binds, prepare: prepare, async: async, allow_retry: allow_retry, materialize_transactions: materialize_transactions, &block)
|
592
|
+
end
|
593
|
+
|
594
|
+
def execute_batch(statements, name = nil, **kwargs)
|
595
|
+
statements.each do |statement|
|
596
|
+
raw_execute(statement, name, **kwargs)
|
597
|
+
end
|
532
598
|
end
|
533
599
|
|
534
600
|
DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
|
@@ -597,21 +663,19 @@ module ActiveRecord
|
|
597
663
|
end
|
598
664
|
end
|
599
665
|
|
600
|
-
def with_multi_statements
|
601
|
-
yield
|
602
|
-
end
|
603
|
-
|
604
666
|
def combine_multi_statements(total_sql)
|
605
667
|
total_sql.join(";\n")
|
606
668
|
end
|
607
669
|
|
608
670
|
# Returns an ActiveRecord::Result instance.
|
609
|
-
def select(sql, name = nil, binds = [], prepare: false, async: false)
|
671
|
+
def select(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false)
|
610
672
|
if async && async_enabled?
|
611
673
|
if current_transaction.joinable?
|
612
674
|
raise AsynchronousQueryInsideTransactionError, "Asynchronous queries are not allowed inside transactions"
|
613
675
|
end
|
614
676
|
|
677
|
+
# We make sure to run query transformers on the original thread
|
678
|
+
sql = preprocess_query(sql)
|
615
679
|
future_result = async.new(
|
616
680
|
pool,
|
617
681
|
sql,
|
@@ -619,19 +683,19 @@ module ActiveRecord
|
|
619
683
|
binds,
|
620
684
|
prepare: prepare,
|
621
685
|
)
|
622
|
-
if supports_concurrent_connections? && current_transaction.
|
686
|
+
if supports_concurrent_connections? && !current_transaction.joinable?
|
623
687
|
future_result.schedule!(ActiveRecord::Base.asynchronous_queries_session)
|
624
688
|
else
|
625
689
|
future_result.execute!(self)
|
626
690
|
end
|
627
|
-
|
628
|
-
end
|
629
|
-
|
630
|
-
result = internal_exec_query(sql, name, binds, prepare: prepare)
|
631
|
-
if async
|
632
|
-
FutureResult.wrap(result)
|
691
|
+
future_result
|
633
692
|
else
|
634
|
-
result
|
693
|
+
result = internal_exec_query(sql, name, binds, prepare: prepare, allow_retry: allow_retry)
|
694
|
+
if async
|
695
|
+
FutureResult.wrap(result)
|
696
|
+
else
|
697
|
+
result
|
698
|
+
end
|
635
699
|
end
|
636
700
|
end
|
637
701
|
|