activerecord 7.1.6 → 7.2.3
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 +839 -2248
- data/README.rdoc +16 -16
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +15 -8
- 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/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 +16 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -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 +7 -1
- 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 +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 +59 -292
- 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 +23 -55
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +5 -25
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -6
- data/lib/active_record/attribute_methods.rb +51 -60
- data/lib/active_record/attributes.rb +93 -68
- data/lib/active_record/autosave_association.rb +25 -32
- data/lib/active_record/base.rb +4 -5
- data/lib/active_record/callbacks.rb +1 -1
- 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 +294 -72
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +34 -17
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +201 -75
- data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +6 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +18 -6
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -62
- data/lib/active_record/connection_adapters/abstract_adapter.rb +46 -44
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +53 -15
- 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 +6 -0
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +19 -18
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -23
- 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/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 +30 -8
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +16 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +36 -26
- 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 +57 -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 +26 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +133 -78
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +15 -15
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -48
- data/lib/active_record/connection_adapters.rb +121 -0
- data/lib/active_record/connection_handling.rb +68 -49
- data/lib/active_record/core.rb +112 -44
- 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 +19 -4
- data/lib/active_record/database_configurations/hash_config.rb +38 -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 +42 -18
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/encryptable_record.rb +4 -4
- data/lib/active_record/encryption/encrypted_attribute_type.rb +25 -5
- data/lib/active_record/encryption/encryptor.rb +35 -19
- 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/enum.rb +31 -13
- data/lib/active_record/errors.rb +49 -23
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +37 -31
- data/lib/active_record/future_result.rb +8 -4
- data/lib/active_record/gem_version.rb +2 -2
- 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 +7 -6
- data/lib/active_record/log_subscriber.rb +0 -21
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +2 -3
- data/lib/active_record/migration/compatibility.rb +5 -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 +87 -77
- data/lib/active_record/model_schema.rb +31 -68
- data/lib/active_record/nested_attributes.rb +11 -3
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +30 -352
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +19 -0
- data/lib/active_record/querying.rb +25 -13
- data/lib/active_record/railtie.rb +39 -57
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +42 -44
- data/lib/active_record/reflection.rb +98 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
- data/lib/active_record/relation/batches.rb +14 -8
- data/lib/active_record/relation/calculations.rb +127 -89
- data/lib/active_record/relation/delegation.rb +8 -11
- data/lib/active_record/relation/finder_methods.rb +26 -12
- 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/association_query_value.rb +10 -2
- data/lib/active_record/relation/predicate_builder.rb +3 -3
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +238 -65
- 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 +15 -21
- data/lib/active_record/relation.rb +508 -74
- data/lib/active_record/result.rb +31 -44
- 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 +48 -20
- data/lib/active_record/schema_migration.rb +30 -14
- data/lib/active_record/scoping/named.rb +1 -0
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +27 -7
- 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 +69 -41
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +8 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
- data/lib/active_record/test_fixtures.rb +86 -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 +73 -15
- 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 +15 -10
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +148 -39
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +3 -1
- 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/crud.rb +2 -0
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +0 -6
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/delete_statement.rb +4 -2
- 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/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +7 -3
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -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 +31 -16
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +16 -10
|
@@ -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
|
|
@@ -43,14 +43,13 @@ module ActiveRecord
|
|
|
43
43
|
|
|
44
44
|
attr_reader :pool
|
|
45
45
|
attr_reader :visitor, :owner, :logger, :lock
|
|
46
|
+
attr_accessor :pinned # :nodoc:
|
|
46
47
|
alias :in_use? :owner
|
|
47
48
|
|
|
48
49
|
def pool=(value)
|
|
49
50
|
return if value.eql?(@pool)
|
|
50
51
|
@schema_cache = nil
|
|
51
52
|
@pool = value
|
|
52
|
-
|
|
53
|
-
@pool.schema_reflection.load!(self) if ActiveRecord.lazily_load_schema_cache
|
|
54
53
|
end
|
|
55
54
|
|
|
56
55
|
set_callback :checkin, :after, :enable_lazy_transactions!
|
|
@@ -136,7 +135,7 @@ module ActiveRecord
|
|
|
136
135
|
@logger = ActiveRecord::Base.logger
|
|
137
136
|
|
|
138
137
|
if deprecated_logger || deprecated_connection_options || deprecated_config
|
|
139
|
-
raise ArgumentError, "when initializing an
|
|
138
|
+
raise ArgumentError, "when initializing an Active Record adapter with a config hash, that should be the only argument"
|
|
140
139
|
end
|
|
141
140
|
else
|
|
142
141
|
# Soft-deprecated for now; we'll probably warn in future.
|
|
@@ -153,6 +152,7 @@ module ActiveRecord
|
|
|
153
152
|
end
|
|
154
153
|
|
|
155
154
|
@owner = nil
|
|
155
|
+
@pinned = false
|
|
156
156
|
@instrumenter = ActiveSupport::Notifications.instrumenter
|
|
157
157
|
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
|
158
158
|
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
@@ -171,22 +171,24 @@ module ActiveRecord
|
|
|
171
171
|
@default_timezone = self.class.validate_default_timezone(@config[:default_timezone])
|
|
172
172
|
|
|
173
173
|
@raw_connection_dirty = false
|
|
174
|
+
@last_activity = nil
|
|
174
175
|
@verified = false
|
|
175
176
|
end
|
|
176
177
|
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
def inspect # :nodoc:
|
|
179
|
+
name_field = " name=#{pool.db_config.name.inspect}" unless pool.db_config.name == "primary"
|
|
180
|
+
shard_field = " shard=#{shard.inspect}" unless shard == :default
|
|
179
181
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
+
"#<#{self.class.name}:#{'%#016x' % (object_id << 1)} env_name=#{pool.db_config.env_name.inspect}#{name_field} role=#{role.inspect}#{shard_field}>"
|
|
183
|
+
end
|
|
182
184
|
|
|
183
185
|
def lock_thread=(lock_thread) # :nodoc:
|
|
184
186
|
@lock =
|
|
185
187
|
case lock_thread
|
|
186
188
|
when Thread
|
|
187
|
-
|
|
189
|
+
ActiveSupport::Concurrency::ThreadLoadInterlockAwareMonitor.new
|
|
188
190
|
when Fiber
|
|
189
|
-
|
|
191
|
+
ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
|
190
192
|
else
|
|
191
193
|
ActiveSupport::Concurrency::NullLock
|
|
192
194
|
end
|
|
@@ -215,14 +217,14 @@ module ActiveRecord
|
|
|
215
217
|
@config[:replica] || false
|
|
216
218
|
end
|
|
217
219
|
|
|
218
|
-
def use_metadata_table?
|
|
219
|
-
@config.fetch(:use_metadata_table, true)
|
|
220
|
-
end
|
|
221
|
-
|
|
222
220
|
def connection_retries
|
|
223
221
|
(@config[:connection_retries] || 1).to_i
|
|
224
222
|
end
|
|
225
223
|
|
|
224
|
+
def verify_timeout
|
|
225
|
+
(@config[:verify_timeout] || 2).to_i
|
|
226
|
+
end
|
|
227
|
+
|
|
226
228
|
def retry_deadline
|
|
227
229
|
if @config[:retry_deadline]
|
|
228
230
|
@config[:retry_deadline].to_f
|
|
@@ -246,22 +248,6 @@ module ActiveRecord
|
|
|
246
248
|
connection_class.current_preventing_writes
|
|
247
249
|
end
|
|
248
250
|
|
|
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
251
|
def prepared_statements?
|
|
266
252
|
@prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
|
|
267
253
|
end
|
|
@@ -327,7 +313,7 @@ module ActiveRecord
|
|
|
327
313
|
end
|
|
328
314
|
|
|
329
315
|
def schema_cache
|
|
330
|
-
@schema_cache ||= BoundSchemaReflection.
|
|
316
|
+
@pool.schema_cache || (@schema_cache ||= BoundSchemaReflection.for_lone_connection(@pool.schema_reflection, self))
|
|
331
317
|
end
|
|
332
318
|
|
|
333
319
|
# this method must only be called while holding connection pool's mutex
|
|
@@ -365,6 +351,13 @@ module ActiveRecord
|
|
|
365
351
|
Process.clock_gettime(Process::CLOCK_MONOTONIC) - @idle_since
|
|
366
352
|
end
|
|
367
353
|
|
|
354
|
+
# Seconds since this connection last communicated with the server
|
|
355
|
+
def seconds_since_last_activity # :nodoc:
|
|
356
|
+
if @raw_connection && @last_activity
|
|
357
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) - @last_activity
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
368
361
|
def unprepared_statement
|
|
369
362
|
cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements
|
|
370
363
|
yield
|
|
@@ -580,7 +573,7 @@ module ActiveRecord
|
|
|
580
573
|
end
|
|
581
574
|
|
|
582
575
|
def return_value_after_insert?(column) # :nodoc:
|
|
583
|
-
column.
|
|
576
|
+
column.auto_populated?
|
|
584
577
|
end
|
|
585
578
|
|
|
586
579
|
def async_enabled? # :nodoc:
|
|
@@ -651,15 +644,6 @@ module ActiveRecord
|
|
|
651
644
|
yield
|
|
652
645
|
end
|
|
653
646
|
|
|
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
647
|
# Override to check all foreign key constraints in a database.
|
|
664
648
|
# The adapter should raise a +ActiveRecord::StatementInvalid+ if foreign key
|
|
665
649
|
# constraints are not met.
|
|
@@ -668,6 +652,13 @@ module ActiveRecord
|
|
|
668
652
|
|
|
669
653
|
# CONNECTION MANAGEMENT ====================================
|
|
670
654
|
|
|
655
|
+
# Checks whether the connection to the database was established. This doesn't
|
|
656
|
+
# include checking whether the database is actually capable of responding, i.e.
|
|
657
|
+
# whether the connection is stale.
|
|
658
|
+
def connected?
|
|
659
|
+
!@raw_connection.nil?
|
|
660
|
+
end
|
|
661
|
+
|
|
671
662
|
# Checks whether the connection to the database is still active. This includes
|
|
672
663
|
# checking whether the database is actually capable of responding, i.e. whether
|
|
673
664
|
# the connection isn't stale.
|
|
@@ -686,6 +677,7 @@ module ActiveRecord
|
|
|
686
677
|
|
|
687
678
|
enable_lazy_transactions!
|
|
688
679
|
@raw_connection_dirty = false
|
|
680
|
+
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
689
681
|
@verified = true
|
|
690
682
|
|
|
691
683
|
reset_transaction(restore: restore_transactions) do
|
|
@@ -705,6 +697,7 @@ module ActiveRecord
|
|
|
705
697
|
end
|
|
706
698
|
end
|
|
707
699
|
|
|
700
|
+
@last_activity = nil
|
|
708
701
|
@verified = false
|
|
709
702
|
|
|
710
703
|
raise translated_exception
|
|
@@ -779,6 +772,7 @@ module ActiveRecord
|
|
|
779
772
|
@raw_connection = @unconfigured_connection
|
|
780
773
|
@unconfigured_connection = nil
|
|
781
774
|
attempt_configure_connection
|
|
775
|
+
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
782
776
|
@verified = true
|
|
783
777
|
return
|
|
784
778
|
end
|
|
@@ -867,7 +861,7 @@ module ActiveRecord
|
|
|
867
861
|
end
|
|
868
862
|
|
|
869
863
|
def database_version # :nodoc:
|
|
870
|
-
|
|
864
|
+
pool.server_version(self)
|
|
871
865
|
end
|
|
872
866
|
|
|
873
867
|
def check_version # :nodoc:
|
|
@@ -878,7 +872,7 @@ module ActiveRecord
|
|
|
878
872
|
# numbered migration that has been executed, or 0 if no schema
|
|
879
873
|
# information is present / the database is empty.
|
|
880
874
|
def schema_version
|
|
881
|
-
migration_context.current_version
|
|
875
|
+
pool.migration_context.current_version
|
|
882
876
|
end
|
|
883
877
|
|
|
884
878
|
class << self
|
|
@@ -1008,6 +1002,9 @@ module ActiveRecord
|
|
|
1008
1002
|
if @verified
|
|
1009
1003
|
# Cool, we're confident the connection's ready to use. (Note this might have
|
|
1010
1004
|
# become true during the above #materialize_transactions.)
|
|
1005
|
+
elsif (last_activity = seconds_since_last_activity) && last_activity < verify_timeout
|
|
1006
|
+
# We haven't actually verified the connection since we acquired it, but it
|
|
1007
|
+
# has been used very recently. We're going to assume it's still okay.
|
|
1011
1008
|
elsif reconnectable
|
|
1012
1009
|
if allow_retry
|
|
1013
1010
|
# Not sure about the connection yet, but if anything goes wrong we can
|
|
@@ -1049,6 +1046,7 @@ module ActiveRecord
|
|
|
1049
1046
|
# Barring a known-retryable error inside the query (regardless of
|
|
1050
1047
|
# whether we were in a _position_ to retry it), we should infer that
|
|
1051
1048
|
# there's likely a real problem with the connection.
|
|
1049
|
+
@last_activity = nil
|
|
1052
1050
|
@verified = false
|
|
1053
1051
|
end
|
|
1054
1052
|
|
|
@@ -1063,6 +1061,7 @@ module ActiveRecord
|
|
|
1063
1061
|
# `with_raw_connection` block only when the block is guaranteed to
|
|
1064
1062
|
# exercise the raw connection.
|
|
1065
1063
|
def verified!
|
|
1064
|
+
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
1066
1065
|
@verified = true
|
|
1067
1066
|
end
|
|
1068
1067
|
|
|
@@ -1148,6 +1147,8 @@ module ActiveRecord
|
|
|
1148
1147
|
statement_name: statement_name,
|
|
1149
1148
|
async: async,
|
|
1150
1149
|
connection: self,
|
|
1150
|
+
transaction: current_transaction.user_transaction.presence,
|
|
1151
|
+
row_count: 0,
|
|
1151
1152
|
&block
|
|
1152
1153
|
)
|
|
1153
1154
|
rescue ActiveRecord::StatementInvalid => ex
|
|
@@ -1211,7 +1212,7 @@ module ActiveRecord
|
|
|
1211
1212
|
#
|
|
1212
1213
|
# This is an internal hook to make possible connection adapters to build
|
|
1213
1214
|
# custom result objects with connection-specific data.
|
|
1214
|
-
def build_result(columns:, rows:, column_types:
|
|
1215
|
+
def build_result(columns:, rows:, column_types: nil)
|
|
1215
1216
|
ActiveRecord::Result.new(columns, rows, column_types)
|
|
1216
1217
|
end
|
|
1217
1218
|
|
|
@@ -1223,6 +1224,7 @@ module ActiveRecord
|
|
|
1223
1224
|
# Implementations may assume this method will only be called while
|
|
1224
1225
|
# holding @lock (or from #initialize).
|
|
1225
1226
|
def configure_connection
|
|
1227
|
+
check_version
|
|
1226
1228
|
end
|
|
1227
1229
|
|
|
1228
1230
|
def attempt_configure_connection
|
|
@@ -170,6 +170,14 @@ 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
|
+
|
|
177
|
+
def return_value_after_insert?(column) # :nodoc:
|
|
178
|
+
supports_insert_returning? ? column.auto_populated? : column.auto_increment?
|
|
179
|
+
end
|
|
180
|
+
|
|
173
181
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
|
174
182
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
|
175
183
|
end
|
|
@@ -214,7 +222,7 @@ module ActiveRecord
|
|
|
214
222
|
update("SET FOREIGN_KEY_CHECKS = 0")
|
|
215
223
|
yield
|
|
216
224
|
ensure
|
|
217
|
-
update("SET FOREIGN_KEY_CHECKS = #{old}")
|
|
225
|
+
update("SET FOREIGN_KEY_CHECKS = #{old}") if active?
|
|
218
226
|
end
|
|
219
227
|
end
|
|
220
228
|
|
|
@@ -225,12 +233,12 @@ module ActiveRecord
|
|
|
225
233
|
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
|
226
234
|
# to write stuff in an abstract way without concerning ourselves about whether it
|
|
227
235
|
# needs to be explicitly freed or not.
|
|
228
|
-
def execute_and_free(sql, name = nil, async: false) # :nodoc:
|
|
236
|
+
def execute_and_free(sql, name = nil, async: false, allow_retry: false) # :nodoc:
|
|
229
237
|
sql = transform_query(sql)
|
|
230
238
|
check_if_write_query(sql)
|
|
231
239
|
|
|
232
240
|
mark_transaction_written_if_write(sql)
|
|
233
|
-
yield raw_execute(sql, name, async: async)
|
|
241
|
+
yield raw_execute(sql, name, async: async, allow_retry: allow_retry)
|
|
234
242
|
end
|
|
235
243
|
|
|
236
244
|
def begin_db_transaction # :nodoc:
|
|
@@ -410,7 +418,11 @@ module ActiveRecord
|
|
|
410
418
|
type ||= column.sql_type
|
|
411
419
|
|
|
412
420
|
unless options.key?(:default)
|
|
413
|
-
options[:default] = column.
|
|
421
|
+
options[:default] = if column.default_function
|
|
422
|
+
-> { column.default_function }
|
|
423
|
+
else
|
|
424
|
+
column.default
|
|
425
|
+
end
|
|
414
426
|
end
|
|
415
427
|
|
|
416
428
|
unless options.key?(:null)
|
|
@@ -635,22 +647,26 @@ module ActiveRecord
|
|
|
635
647
|
end
|
|
636
648
|
|
|
637
649
|
def build_insert_sql(insert) # :nodoc:
|
|
638
|
-
|
|
650
|
+
# Can use any column as it will be assigned to itself.
|
|
651
|
+
no_op_column = quote_column_name(insert.keys.first) if insert.keys.first
|
|
639
652
|
|
|
640
653
|
# MySQL 8.0.19 replaces `VALUES(<expression>)` clauses with row and column alias names, see https://dev.mysql.com/worklog/task/?id=6312 .
|
|
641
654
|
# then MySQL 8.0.20 deprecates the `VALUES(<expression>)` see https://dev.mysql.com/worklog/task/?id=13325 .
|
|
642
655
|
if supports_insert_raw_alias_syntax?
|
|
643
|
-
|
|
656
|
+
quoted_table_name = insert.model.quoted_table_name
|
|
657
|
+
values_alias = quote_table_name("#{insert.model.table_name.parameterize}_values")
|
|
644
658
|
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"
|
|
645
659
|
|
|
646
660
|
if insert.skip_duplicates?
|
|
647
|
-
|
|
661
|
+
if no_op_column
|
|
662
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{quoted_table_name}.#{no_op_column}"
|
|
663
|
+
end
|
|
648
664
|
elsif insert.update_duplicates?
|
|
649
665
|
if insert.raw_update_sql?
|
|
650
666
|
sql = +"INSERT #{insert.into} #{insert.values_list} ON DUPLICATE KEY UPDATE #{insert.raw_update_sql}"
|
|
651
667
|
else
|
|
652
668
|
sql << " ON DUPLICATE KEY UPDATE "
|
|
653
|
-
sql << insert.touch_model_timestamps_unless { |column| "#{
|
|
669
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{quoted_table_name}.#{column}<=>#{values_alias}.#{column}" }
|
|
654
670
|
sql << insert.updatable_columns.map { |column| "#{column}=#{values_alias}.#{column}" }.join(",")
|
|
655
671
|
end
|
|
656
672
|
end
|
|
@@ -658,7 +674,9 @@ module ActiveRecord
|
|
|
658
674
|
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
|
659
675
|
|
|
660
676
|
if insert.skip_duplicates?
|
|
661
|
-
|
|
677
|
+
if no_op_column
|
|
678
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
|
679
|
+
end
|
|
662
680
|
elsif insert.update_duplicates?
|
|
663
681
|
sql << " ON DUPLICATE KEY UPDATE "
|
|
664
682
|
if insert.raw_update_sql?
|
|
@@ -670,12 +688,24 @@ module ActiveRecord
|
|
|
670
688
|
end
|
|
671
689
|
end
|
|
672
690
|
|
|
691
|
+
sql << " RETURNING #{insert.returning}" if insert.returning
|
|
673
692
|
sql
|
|
674
693
|
end
|
|
675
694
|
|
|
676
695
|
def check_version # :nodoc:
|
|
677
696
|
if database_version < "5.5.8"
|
|
678
|
-
raise "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
|
|
697
|
+
raise DatabaseVersionError, "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
|
|
698
|
+
end
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
#--
|
|
702
|
+
# QUOTING ==================================================
|
|
703
|
+
#++
|
|
704
|
+
|
|
705
|
+
# Quotes strings for use in SQL input.
|
|
706
|
+
def quote_string(string)
|
|
707
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |connection|
|
|
708
|
+
connection.escape(string)
|
|
679
709
|
end
|
|
680
710
|
end
|
|
681
711
|
|
|
@@ -737,9 +767,7 @@ module ActiveRecord
|
|
|
737
767
|
|
|
738
768
|
private
|
|
739
769
|
def strip_whitespace_characters(expression)
|
|
740
|
-
expression
|
|
741
|
-
expression = expression.gsub(/\s{2,}/, " ")
|
|
742
|
-
expression
|
|
770
|
+
expression.gsub('\\\n', "").gsub("x0A", "").squish
|
|
743
771
|
end
|
|
744
772
|
|
|
745
773
|
def extended_type_map_key
|
|
@@ -754,7 +782,11 @@ module ActiveRecord
|
|
|
754
782
|
return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
|
|
755
783
|
|
|
756
784
|
@affected_rows_before_warnings = @raw_connection.affected_rows
|
|
785
|
+
warning_count = @raw_connection.warning_count
|
|
757
786
|
result = @raw_connection.query("SHOW WARNINGS")
|
|
787
|
+
result = [
|
|
788
|
+
["Warning", nil, "Query had warning_count=#{warning_count} but ‘SHOW WARNINGS’ did not return the warnings. Check MySQL logs or database configuration."],
|
|
789
|
+
] if result.count == 0
|
|
758
790
|
result.each do |level, code, message|
|
|
759
791
|
warning = SQLWarning.new(message, code, level, sql, @pool)
|
|
760
792
|
next if warning_ignored?(warning)
|
|
@@ -776,6 +808,7 @@ module ActiveRecord
|
|
|
776
808
|
ER_DB_CREATE_EXISTS = 1007
|
|
777
809
|
ER_FILSORT_ABORT = 1028
|
|
778
810
|
ER_DUP_ENTRY = 1062
|
|
811
|
+
ER_SERVER_SHUTDOWN = 1053
|
|
779
812
|
ER_NOT_NULL_VIOLATION = 1048
|
|
780
813
|
ER_NO_REFERENCED_ROW = 1216
|
|
781
814
|
ER_ROW_IS_REFERENCED = 1217
|
|
@@ -804,7 +837,7 @@ module ActiveRecord
|
|
|
804
837
|
else
|
|
805
838
|
super
|
|
806
839
|
end
|
|
807
|
-
when ER_CONNECTION_KILLED, CR_SERVER_GONE_ERROR, CR_SERVER_LOST, ER_CLIENT_INTERACTION_TIMEOUT
|
|
840
|
+
when ER_CONNECTION_KILLED, ER_SERVER_SHUTDOWN, CR_SERVER_GONE_ERROR, CR_SERVER_LOST, ER_CLIENT_INTERACTION_TIMEOUT
|
|
808
841
|
ConnectionFailed.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
809
842
|
when ER_DB_CREATE_EXISTS
|
|
810
843
|
DatabaseAlreadyExists.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
@@ -894,6 +927,7 @@ module ActiveRecord
|
|
|
894
927
|
end
|
|
895
928
|
|
|
896
929
|
def configure_connection
|
|
930
|
+
super
|
|
897
931
|
variables = @config.fetch(:variables, {}).stringify_keys
|
|
898
932
|
|
|
899
933
|
# Increase timeout so the server doesn't disconnect us.
|
|
@@ -1001,7 +1035,11 @@ module ActiveRecord
|
|
|
1001
1035
|
end
|
|
1002
1036
|
|
|
1003
1037
|
def version_string(full_version_string)
|
|
1004
|
-
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)
|
|
1038
|
+
if full_version_string && matches = full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)
|
|
1039
|
+
matches[1]
|
|
1040
|
+
else
|
|
1041
|
+
raise DatabaseVersionError, "Unable to parse MySQL version from #{full_version_string.inspect}"
|
|
1042
|
+
end
|
|
1005
1043
|
end
|
|
1006
1044
|
end
|
|
1007
1045
|
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
|
|
@@ -6,9 +6,52 @@ module ActiveRecord
|
|
|
6
6
|
module ConnectionAdapters
|
|
7
7
|
module MySQL
|
|
8
8
|
module Quoting # :nodoc:
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
9
11
|
QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
|
|
10
12
|
QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
|
|
11
13
|
|
|
14
|
+
module ClassMethods # :nodoc:
|
|
15
|
+
def column_name_matcher
|
|
16
|
+
/
|
|
17
|
+
\A
|
|
18
|
+
(
|
|
19
|
+
(?:
|
|
20
|
+
# `table_name`.`column_name` | function(one or no argument)
|
|
21
|
+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
|
22
|
+
)
|
|
23
|
+
(?:(?:\s+AS)?\s+(?:\w+|`\w+`))?
|
|
24
|
+
)
|
|
25
|
+
(?:\s*,\s*\g<1>)*
|
|
26
|
+
\z
|
|
27
|
+
/ix
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def column_name_with_order_matcher
|
|
31
|
+
/
|
|
32
|
+
\A
|
|
33
|
+
(
|
|
34
|
+
(?:
|
|
35
|
+
# `table_name`.`column_name` | function(one or no argument)
|
|
36
|
+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
|
37
|
+
)
|
|
38
|
+
(?:\s+COLLATE\s+(?:\w+|"\w+"))?
|
|
39
|
+
(?:\s+ASC|\s+DESC)?
|
|
40
|
+
)
|
|
41
|
+
(?:\s*,\s*\g<1>)*
|
|
42
|
+
\z
|
|
43
|
+
/ix
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def quote_column_name(name)
|
|
47
|
+
QUOTED_COLUMN_NAMES[name] ||= "`#{name.to_s.gsub('`', '``')}`".freeze
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def quote_table_name(name)
|
|
51
|
+
QUOTED_TABLE_NAMES[name] ||= "`#{name.to_s.gsub('`', '``').gsub(".", "`.`")}`".freeze
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
12
55
|
def cast_bound_value(value)
|
|
13
56
|
case value
|
|
14
57
|
when Rational
|
|
@@ -21,22 +64,11 @@ module ActiveRecord
|
|
|
21
64
|
"1"
|
|
22
65
|
when false
|
|
23
66
|
"0"
|
|
24
|
-
when ActiveSupport::Duration
|
|
25
|
-
warn_quote_duration_deprecated
|
|
26
|
-
value.to_s
|
|
27
67
|
else
|
|
28
68
|
value
|
|
29
69
|
end
|
|
30
70
|
end
|
|
31
71
|
|
|
32
|
-
def quote_column_name(name)
|
|
33
|
-
QUOTED_COLUMN_NAMES[name] ||= "`#{super.gsub('`', '``')}`"
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def quote_table_name(name)
|
|
37
|
-
QUOTED_TABLE_NAMES[name] ||= super.gsub(".", "`.`").freeze
|
|
38
|
-
end
|
|
39
|
-
|
|
40
72
|
def unquoted_true
|
|
41
73
|
1
|
|
42
74
|
end
|
|
@@ -90,43 +122,6 @@ module ActiveRecord
|
|
|
90
122
|
super
|
|
91
123
|
end
|
|
92
124
|
end
|
|
93
|
-
|
|
94
|
-
def column_name_matcher
|
|
95
|
-
COLUMN_NAME
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def column_name_with_order_matcher
|
|
99
|
-
COLUMN_NAME_WITH_ORDER
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
COLUMN_NAME = /
|
|
103
|
-
\A
|
|
104
|
-
(
|
|
105
|
-
(?:
|
|
106
|
-
# `table_name`.`column_name` | function(one or no argument)
|
|
107
|
-
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
|
108
|
-
)
|
|
109
|
-
(?:(?:\s+AS)?\s+(?:\w+|`\w+`))?
|
|
110
|
-
)
|
|
111
|
-
(?:\s*,\s*\g<1>)*
|
|
112
|
-
\z
|
|
113
|
-
/ix
|
|
114
|
-
|
|
115
|
-
COLUMN_NAME_WITH_ORDER = /
|
|
116
|
-
\A
|
|
117
|
-
(
|
|
118
|
-
(?:
|
|
119
|
-
# `table_name`.`column_name` | function(one or no argument)
|
|
120
|
-
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
|
121
|
-
)
|
|
122
|
-
(?:\s+COLLATE\s+(?:\w+|"\w+"))?
|
|
123
|
-
(?:\s+ASC|\s+DESC)?
|
|
124
|
-
)
|
|
125
|
-
(?:\s*,\s*\g<1>)*
|
|
126
|
-
\z
|
|
127
|
-
/ix
|
|
128
|
-
|
|
129
|
-
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
|
130
125
|
end
|
|
131
126
|
end
|
|
132
127
|
end
|
|
@@ -68,6 +68,12 @@ module ActiveRecord
|
|
|
68
68
|
|
|
69
69
|
IndexDefinition.new(*index, **options)
|
|
70
70
|
end
|
|
71
|
+
rescue StatementInvalid => e
|
|
72
|
+
if e.message.match?(/Table '.+' doesn't exist/)
|
|
73
|
+
[]
|
|
74
|
+
else
|
|
75
|
+
raise
|
|
76
|
+
end
|
|
71
77
|
end
|
|
72
78
|
|
|
73
79
|
def remove_column(table_name, column_name, type = nil, **options)
|
|
@@ -6,21 +6,16 @@ module ActiveRecord
|
|
|
6
6
|
module DatabaseStatements
|
|
7
7
|
# Returns an ActiveRecord::Result instance.
|
|
8
8
|
def select_all(*, **) # :nodoc:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
else
|
|
14
|
-
super
|
|
15
|
-
end
|
|
16
|
-
conn.abandon_results!
|
|
9
|
+
if ExplainRegistry.collect? && prepared_statements
|
|
10
|
+
unprepared_statement { super }
|
|
11
|
+
else
|
|
12
|
+
super
|
|
17
13
|
end
|
|
18
|
-
result
|
|
19
14
|
end
|
|
20
15
|
|
|
21
|
-
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :nodoc:
|
|
16
|
+
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false) # :nodoc:
|
|
22
17
|
if without_prepared_statement?(binds)
|
|
23
|
-
execute_and_free(sql, name, async: async) do |result|
|
|
18
|
+
execute_and_free(sql, name, async: async, allow_retry: allow_retry) do |result|
|
|
24
19
|
if result
|
|
25
20
|
build_result(columns: result.fields, rows: result.to_a)
|
|
26
21
|
else
|
|
@@ -28,7 +23,7 @@ module ActiveRecord
|
|
|
28
23
|
end
|
|
29
24
|
end
|
|
30
25
|
else
|
|
31
|
-
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare, async: async) do |_, result|
|
|
26
|
+
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare, async: async, allow_retry: allow_retry) do |_, result|
|
|
32
27
|
if result
|
|
33
28
|
build_result(columns: result.fields, rows: result.to_a)
|
|
34
29
|
else
|
|
@@ -60,13 +55,16 @@ module ActiveRecord
|
|
|
60
55
|
combine_multi_statements(statements).each do |statement|
|
|
61
56
|
with_raw_connection do |conn|
|
|
62
57
|
raw_execute(statement, name)
|
|
63
|
-
conn.abandon_results!
|
|
64
58
|
end
|
|
65
59
|
end
|
|
66
60
|
end
|
|
67
61
|
|
|
68
62
|
def last_inserted_id(result)
|
|
69
|
-
|
|
63
|
+
if supports_insert_returning?
|
|
64
|
+
super
|
|
65
|
+
else
|
|
66
|
+
@raw_connection&.last_id
|
|
67
|
+
end
|
|
70
68
|
end
|
|
71
69
|
|
|
72
70
|
def multi_statements_enabled?
|
|
@@ -94,18 +92,20 @@ module ActiveRecord
|
|
|
94
92
|
end
|
|
95
93
|
|
|
96
94
|
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
|
|
97
|
-
log(sql, name, async: async) do
|
|
95
|
+
log(sql, name, async: async) do |notification_payload|
|
|
98
96
|
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
|
99
97
|
sync_timezone_changes(conn)
|
|
100
98
|
result = conn.query(sql)
|
|
99
|
+
conn.abandon_results!
|
|
101
100
|
verified!
|
|
102
101
|
handle_warnings(sql)
|
|
102
|
+
notification_payload[:row_count] = result&.size || 0
|
|
103
103
|
result
|
|
104
104
|
end
|
|
105
105
|
end
|
|
106
106
|
end
|
|
107
107
|
|
|
108
|
-
def exec_stmt_and_free(sql, name, binds, cache_stmt: false, async: false)
|
|
108
|
+
def exec_stmt_and_free(sql, name, binds, cache_stmt: false, async: false, allow_retry: false)
|
|
109
109
|
sql = transform_query(sql)
|
|
110
110
|
check_if_write_query(sql)
|
|
111
111
|
|
|
@@ -113,8 +113,8 @@ module ActiveRecord
|
|
|
113
113
|
|
|
114
114
|
type_casted_binds = type_casted_binds(binds)
|
|
115
115
|
|
|
116
|
-
log(sql, name, binds, type_casted_binds, async: async) do
|
|
117
|
-
with_raw_connection do |conn|
|
|
116
|
+
log(sql, name, binds, type_casted_binds, async: async) do |notification_payload|
|
|
117
|
+
with_raw_connection(allow_retry: allow_retry) do |conn|
|
|
118
118
|
sync_timezone_changes(conn)
|
|
119
119
|
|
|
120
120
|
if cache_stmt
|
|
@@ -139,6 +139,7 @@ module ActiveRecord
|
|
|
139
139
|
end
|
|
140
140
|
|
|
141
141
|
ret = yield stmt, result
|
|
142
|
+
notification_payload[:row_count] = result&.size || 0
|
|
142
143
|
result.free if result
|
|
143
144
|
stmt.close unless cache_stmt
|
|
144
145
|
ret
|