activerecord 7.2.2.1 → 8.0.5
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 +523 -677
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +1 -0
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/association.rb +34 -10
- data/lib/active_record/associations/belongs_to_association.rb +18 -2
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/collection_association.rb +10 -8
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/associations/join_dependency.rb +2 -2
- data/lib/active_record/associations/preloader/association.rb +2 -2
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +34 -4
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/primary_key.rb +4 -8
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -12
- data/lib/active_record/attribute_methods.rb +24 -19
- data/lib/active_record/attributes.rb +37 -26
- data/lib/active_record/autosave_association.rb +91 -39
- data/lib/active_record/base.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +34 -25
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +55 -47
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +91 -44
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +25 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- 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 +40 -10
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +92 -70
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +35 -46
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +50 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +84 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +9 -9
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +72 -43
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- 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 +20 -24
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +60 -17
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +61 -99
- data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +80 -100
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +10 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +63 -17
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -18
- data/lib/active_record/connection_adapters.rb +0 -56
- data/lib/active_record/connection_handling.rb +35 -9
- data/lib/active_record/core.rb +57 -22
- data/lib/active_record/counter_cache.rb +1 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/database_configurations/database_config.rb +4 -0
- data/lib/active_record/database_configurations/hash_config.rb +16 -2
- data/lib/active_record/delegated_type.rb +18 -18
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +5 -5
- data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
- data/lib/active_record/encryption/encryptor.rb +37 -28
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +8 -1
- data/lib/active_record/enum.rb +22 -34
- data/lib/active_record/errors.rb +16 -8
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +0 -2
- data/lib/active_record/future_result.rb +15 -9
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/insert_all.rb +3 -3
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +5 -11
- data/lib/active_record/migration/command_recorder.rb +32 -12
- data/lib/active_record/migration/compatibility.rb +5 -2
- data/lib/active_record/migration.rb +40 -43
- data/lib/active_record/model_schema.rb +3 -4
- data/lib/active_record/nested_attributes.rb +4 -6
- data/lib/active_record/persistence.rb +128 -130
- data/lib/active_record/query_logs.rb +106 -50
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +12 -12
- data/lib/active_record/railtie.rb +4 -28
- data/lib/active_record/railties/databases.rake +11 -34
- data/lib/active_record/reflection.rb +18 -21
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +132 -72
- data/lib/active_record/relation/calculations.rb +71 -65
- data/lib/active_record/relation/delegation.rb +25 -14
- data/lib/active_record/relation/finder_methods.rb +32 -31
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -0
- 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 +13 -0
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +121 -70
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +9 -3
- data/lib/active_record/relation.rb +95 -67
- data/lib/active_record/result.rb +66 -4
- data/lib/active_record/sanitization.rb +7 -6
- data/lib/active_record/schema_dumper.rb +34 -11
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +7 -6
- data/lib/active_record/statement_cache.rb +14 -14
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/table_metadata.rb +1 -3
- data/lib/active_record/tasks/database_tasks.rb +69 -60
- data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
- data/lib/active_record/tasks/postgresql_database_tasks.rb +9 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +12 -0
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transactions.rb +8 -7
- data/lib/active_record/type/serialized.rb +5 -0
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +22 -49
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/crud.rb +2 -0
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/node.rb +1 -1
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/predications.rb +1 -3
- data/lib/arel/select_manager.rb +6 -2
- data/lib/arel/table.rb +3 -7
- data/lib/arel/update_manager.rb +5 -0
- data/lib/arel/visitors/dot.rb +2 -0
- data/lib/arel/visitors/to_sql.rb +3 -1
- metadata +11 -15
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
|
@@ -186,6 +186,9 @@ module ActiveRecord
|
|
|
186
186
|
# Join tables for {ActiveRecord::Base.has_and_belongs_to_many}[rdoc-ref:Associations::ClassMethods#has_and_belongs_to_many] should set it to false.
|
|
187
187
|
#
|
|
188
188
|
# A Symbol can be used to specify the type of the generated primary key column.
|
|
189
|
+
#
|
|
190
|
+
# A Hash can be used to specify the generated primary key column creation options.
|
|
191
|
+
# See {add_column}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_column] for available options.
|
|
189
192
|
# [<tt>:primary_key</tt>]
|
|
190
193
|
# The name of the primary key, if one is to be added automatically.
|
|
191
194
|
# Defaults to +id+. If <tt>:id</tt> is false, then this option is ignored.
|
|
@@ -345,6 +348,15 @@ module ActiveRecord
|
|
|
345
348
|
# # Creates a table called 'assemblies_parts' with no id.
|
|
346
349
|
# create_join_table(:assemblies, :parts)
|
|
347
350
|
#
|
|
351
|
+
# # Creates a table called 'paper_boxes_papers' with no id.
|
|
352
|
+
# create_join_table('papers', 'paper_boxes')
|
|
353
|
+
#
|
|
354
|
+
# A duplicate prefix is combined into a single prefix. This is useful for
|
|
355
|
+
# namespaced models like Music::Artist and Music::Record:
|
|
356
|
+
#
|
|
357
|
+
# # Creates a table called 'music_artists_records' with no id.
|
|
358
|
+
# create_join_table('music_artists', 'music_records')
|
|
359
|
+
#
|
|
348
360
|
# You can pass an +options+ hash which can include the following keys:
|
|
349
361
|
# [<tt>:table_name</tt>]
|
|
350
362
|
# Sets the table name, overriding the default.
|
|
@@ -516,7 +528,7 @@ module ActiveRecord
|
|
|
516
528
|
raise NotImplementedError, "rename_table is not implemented"
|
|
517
529
|
end
|
|
518
530
|
|
|
519
|
-
# Drops a table from the database.
|
|
531
|
+
# Drops a table or tables from the database.
|
|
520
532
|
#
|
|
521
533
|
# [<tt>:force</tt>]
|
|
522
534
|
# Set to +:cascade+ to drop dependent objects as well.
|
|
@@ -527,17 +539,19 @@ module ActiveRecord
|
|
|
527
539
|
#
|
|
528
540
|
# Although this command ignores most +options+ and the block if one is given,
|
|
529
541
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
|
530
|
-
# In that case, +options+ and the block will be used by #create_table.
|
|
531
|
-
def drop_table(
|
|
532
|
-
|
|
533
|
-
|
|
542
|
+
# In that case, +options+ and the block will be used by #create_table except if you provide more than one table which is not supported.
|
|
543
|
+
def drop_table(*table_names, **options)
|
|
544
|
+
table_names.each do |table_name|
|
|
545
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
|
546
|
+
execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
|
|
547
|
+
end
|
|
534
548
|
end
|
|
535
549
|
|
|
536
550
|
# Add a new +type+ column named +column_name+ to +table_name+.
|
|
537
551
|
#
|
|
538
552
|
# See {ActiveRecord::ConnectionAdapters::TableDefinition.column}[rdoc-ref:ActiveRecord::ConnectionAdapters::TableDefinition#column].
|
|
539
553
|
#
|
|
540
|
-
# The +type+ parameter is normally one of the
|
|
554
|
+
# The +type+ parameter is normally one of the migration's native types,
|
|
541
555
|
# which is one of the following:
|
|
542
556
|
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
|
|
543
557
|
# <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:numeric</tt>,
|
|
@@ -844,6 +858,16 @@ module ActiveRecord
|
|
|
844
858
|
#
|
|
845
859
|
# Note: only supported by PostgreSQL.
|
|
846
860
|
#
|
|
861
|
+
# ====== Creating an index where NULLs are treated equally
|
|
862
|
+
#
|
|
863
|
+
# add_index(:people, :last_name, nulls_not_distinct: true)
|
|
864
|
+
#
|
|
865
|
+
# generates:
|
|
866
|
+
#
|
|
867
|
+
# CREATE INDEX index_people_on_last_name ON people (last_name) NULLS NOT DISTINCT
|
|
868
|
+
#
|
|
869
|
+
# Note: only supported by PostgreSQL version 15.0.0 and greater.
|
|
870
|
+
#
|
|
847
871
|
# ====== Creating an index with a specific method
|
|
848
872
|
#
|
|
849
873
|
# add_index(:developers, :name, using: 'btree')
|
|
@@ -1313,7 +1337,6 @@ module ActiveRecord
|
|
|
1313
1337
|
execute schema_creation.accept(at)
|
|
1314
1338
|
end
|
|
1315
1339
|
|
|
1316
|
-
|
|
1317
1340
|
# Checks to see if a check constraint exists on a table for a given check constraint definition.
|
|
1318
1341
|
#
|
|
1319
1342
|
# check_constraint_exists?(:products, name: "price_check")
|
|
@@ -1325,6 +1348,13 @@ module ActiveRecord
|
|
|
1325
1348
|
check_constraint_for(table_name, **options).present?
|
|
1326
1349
|
end
|
|
1327
1350
|
|
|
1351
|
+
def remove_constraint(table_name, constraint_name) # :nodoc:
|
|
1352
|
+
at = create_alter_table(table_name)
|
|
1353
|
+
at.drop_constraint(constraint_name)
|
|
1354
|
+
|
|
1355
|
+
execute schema_creation.accept(at)
|
|
1356
|
+
end
|
|
1357
|
+
|
|
1328
1358
|
def dump_schema_information # :nodoc:
|
|
1329
1359
|
versions = pool.schema_migration.versions
|
|
1330
1360
|
insert_versions_sql(versions) if versions.any?
|
|
@@ -1530,11 +1560,11 @@ module ActiveRecord
|
|
|
1530
1560
|
non_combinable_operations = []
|
|
1531
1561
|
|
|
1532
1562
|
operations.each do |command, args|
|
|
1533
|
-
|
|
1563
|
+
args.shift # remove table_name
|
|
1534
1564
|
method = :"#{command}_for_alter"
|
|
1535
1565
|
|
|
1536
1566
|
if respond_to?(method, true)
|
|
1537
|
-
sqls, procs = Array(send(method,
|
|
1567
|
+
sqls, procs = Array(send(method, table_name, *args)).partition { |v| v.is_a?(String) }
|
|
1538
1568
|
sql_fragments.concat(sqls)
|
|
1539
1569
|
non_combinable_operations.concat(procs)
|
|
1540
1570
|
else
|
|
@@ -1542,7 +1572,7 @@ module ActiveRecord
|
|
|
1542
1572
|
non_combinable_operations.each(&:call)
|
|
1543
1573
|
sql_fragments = []
|
|
1544
1574
|
non_combinable_operations = []
|
|
1545
|
-
send(command,
|
|
1575
|
+
send(command, table_name, *args)
|
|
1546
1576
|
end
|
|
1547
1577
|
end
|
|
1548
1578
|
|
|
@@ -448,10 +448,14 @@ module ActiveRecord
|
|
|
448
448
|
# = Active Record Real \Transaction
|
|
449
449
|
class RealTransaction < Transaction
|
|
450
450
|
def materialize!
|
|
451
|
-
if
|
|
452
|
-
|
|
451
|
+
if joinable?
|
|
452
|
+
if isolation_level
|
|
453
|
+
connection.begin_isolated_db_transaction(isolation_level)
|
|
454
|
+
else
|
|
455
|
+
connection.begin_db_transaction
|
|
456
|
+
end
|
|
453
457
|
else
|
|
454
|
-
connection.
|
|
458
|
+
connection.begin_deferred_transaction(isolation_level)
|
|
455
459
|
end
|
|
456
460
|
|
|
457
461
|
super
|
|
@@ -472,13 +476,19 @@ module ActiveRecord
|
|
|
472
476
|
end
|
|
473
477
|
|
|
474
478
|
def rollback
|
|
475
|
-
|
|
479
|
+
if materialized?
|
|
480
|
+
connection.rollback_db_transaction
|
|
481
|
+
connection.reset_isolation_level if isolation_level
|
|
482
|
+
end
|
|
476
483
|
@state.full_rollback!
|
|
477
484
|
@instrumenter.finish(:rollback) if materialized?
|
|
478
485
|
end
|
|
479
486
|
|
|
480
487
|
def commit
|
|
481
|
-
|
|
488
|
+
if materialized?
|
|
489
|
+
connection.commit_db_transaction
|
|
490
|
+
connection.reset_isolation_level if isolation_level
|
|
491
|
+
end
|
|
482
492
|
@state.full_commit!
|
|
483
493
|
@instrumenter.finish(:commit) if materialized?
|
|
484
494
|
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "set"
|
|
4
3
|
require "active_record/connection_adapters/sql_type_metadata"
|
|
5
4
|
require "active_record/connection_adapters/abstract/schema_dumper"
|
|
6
5
|
require "active_record/connection_adapters/abstract/schema_creation"
|
|
@@ -43,6 +42,7 @@ module ActiveRecord
|
|
|
43
42
|
|
|
44
43
|
attr_reader :pool
|
|
45
44
|
attr_reader :visitor, :owner, :logger, :lock
|
|
45
|
+
attr_accessor :pinned # :nodoc:
|
|
46
46
|
alias :in_use? :owner
|
|
47
47
|
|
|
48
48
|
def pool=(value)
|
|
@@ -151,7 +151,7 @@ module ActiveRecord
|
|
|
151
151
|
end
|
|
152
152
|
|
|
153
153
|
@owner = nil
|
|
154
|
-
@
|
|
154
|
+
@pinned = false
|
|
155
155
|
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
|
156
156
|
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
157
157
|
@visitor = arel_visitor
|
|
@@ -169,6 +169,7 @@ module ActiveRecord
|
|
|
169
169
|
@default_timezone = self.class.validate_default_timezone(@config[:default_timezone])
|
|
170
170
|
|
|
171
171
|
@raw_connection_dirty = false
|
|
172
|
+
@last_activity = nil
|
|
172
173
|
@verified = false
|
|
173
174
|
end
|
|
174
175
|
|
|
@@ -191,19 +192,6 @@ module ActiveRecord
|
|
|
191
192
|
end
|
|
192
193
|
end
|
|
193
194
|
|
|
194
|
-
EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
|
|
195
|
-
EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze # :nodoc:
|
|
196
|
-
private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
|
|
197
|
-
def with_instrumenter(instrumenter, &block) # :nodoc:
|
|
198
|
-
Thread.handle_interrupt(EXCEPTION_NEVER) do
|
|
199
|
-
previous_instrumenter = @instrumenter
|
|
200
|
-
@instrumenter = instrumenter
|
|
201
|
-
Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
|
|
202
|
-
ensure
|
|
203
|
-
@instrumenter = previous_instrumenter
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
|
|
207
195
|
def check_if_write_query(sql) # :nodoc:
|
|
208
196
|
if preventing_writes? && write_query?(sql)
|
|
209
197
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
|
@@ -218,6 +206,10 @@ module ActiveRecord
|
|
|
218
206
|
(@config[:connection_retries] || 1).to_i
|
|
219
207
|
end
|
|
220
208
|
|
|
209
|
+
def verify_timeout
|
|
210
|
+
(@config[:verify_timeout] || 2).to_i
|
|
211
|
+
end
|
|
212
|
+
|
|
221
213
|
def retry_deadline
|
|
222
214
|
if @config[:retry_deadline]
|
|
223
215
|
@config[:retry_deadline].to_f
|
|
@@ -236,9 +228,9 @@ module ActiveRecord
|
|
|
236
228
|
# the value of +current_preventing_writes+.
|
|
237
229
|
def preventing_writes?
|
|
238
230
|
return true if replica?
|
|
239
|
-
return false if
|
|
231
|
+
return false if connection_descriptor.nil?
|
|
240
232
|
|
|
241
|
-
|
|
233
|
+
connection_descriptor.current_preventing_writes
|
|
242
234
|
end
|
|
243
235
|
|
|
244
236
|
def prepared_statements?
|
|
@@ -289,8 +281,8 @@ module ActiveRecord
|
|
|
289
281
|
@owner = ActiveSupport::IsolatedExecutionState.context
|
|
290
282
|
end
|
|
291
283
|
|
|
292
|
-
def
|
|
293
|
-
@pool.
|
|
284
|
+
def connection_descriptor # :nodoc:
|
|
285
|
+
@pool.connection_descriptor
|
|
294
286
|
end
|
|
295
287
|
|
|
296
288
|
# The role (e.g. +:writing+) for the current connection. In a
|
|
@@ -344,6 +336,13 @@ module ActiveRecord
|
|
|
344
336
|
Process.clock_gettime(Process::CLOCK_MONOTONIC) - @idle_since
|
|
345
337
|
end
|
|
346
338
|
|
|
339
|
+
# Seconds since this connection last communicated with the server
|
|
340
|
+
def seconds_since_last_activity # :nodoc:
|
|
341
|
+
if @raw_connection && @last_activity
|
|
342
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) - @last_activity
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
347
346
|
def unprepared_statement
|
|
348
347
|
cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements
|
|
349
348
|
yield
|
|
@@ -576,23 +575,31 @@ module ActiveRecord
|
|
|
576
575
|
end
|
|
577
576
|
|
|
578
577
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
579
|
-
def create_enum(
|
|
578
|
+
def create_enum(...) # :nodoc:
|
|
580
579
|
end
|
|
581
580
|
|
|
582
581
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
583
|
-
def drop_enum(
|
|
582
|
+
def drop_enum(...) # :nodoc:
|
|
584
583
|
end
|
|
585
584
|
|
|
586
585
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
587
|
-
def rename_enum(
|
|
586
|
+
def rename_enum(...) # :nodoc:
|
|
588
587
|
end
|
|
589
588
|
|
|
590
589
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
591
|
-
def add_enum_value(
|
|
590
|
+
def add_enum_value(...) # :nodoc:
|
|
592
591
|
end
|
|
593
592
|
|
|
594
593
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
595
|
-
def rename_enum_value(
|
|
594
|
+
def rename_enum_value(...) # :nodoc:
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
# This is meant to be implemented by the adapters that support virtual tables
|
|
598
|
+
def create_virtual_table(*) # :nodoc:
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
# This is meant to be implemented by the adapters that support virtual tables
|
|
602
|
+
def drop_virtual_table(*) # :nodoc:
|
|
596
603
|
end
|
|
597
604
|
|
|
598
605
|
def advisory_locks_enabled? # :nodoc:
|
|
@@ -659,32 +666,33 @@ module ActiveRecord
|
|
|
659
666
|
deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline
|
|
660
667
|
|
|
661
668
|
@lock.synchronize do
|
|
662
|
-
|
|
669
|
+
attempt_configure_connection do
|
|
670
|
+
reconnect
|
|
663
671
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
672
|
+
enable_lazy_transactions!
|
|
673
|
+
@raw_connection_dirty = false
|
|
674
|
+
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
675
|
+
@verified = true
|
|
667
676
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
677
|
+
reset_transaction(restore: restore_transactions) do
|
|
678
|
+
clear_cache!(new_connection: true)
|
|
679
|
+
configure_connection
|
|
680
|
+
end
|
|
681
|
+
rescue => original_exception
|
|
682
|
+
translated_exception = translate_exception_class(original_exception, nil, nil)
|
|
683
|
+
retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
675
684
|
|
|
676
|
-
|
|
677
|
-
|
|
685
|
+
if !retry_deadline_exceeded && retries_available > 0
|
|
686
|
+
retries_available -= 1
|
|
678
687
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
688
|
+
if retryable_connection_error?(translated_exception)
|
|
689
|
+
backoff(connection_retries - retries_available)
|
|
690
|
+
retry
|
|
691
|
+
end
|
|
682
692
|
end
|
|
683
|
-
end
|
|
684
693
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
raise translated_exception
|
|
694
|
+
raise translated_exception
|
|
695
|
+
end
|
|
688
696
|
end
|
|
689
697
|
end
|
|
690
698
|
|
|
@@ -692,6 +700,8 @@ module ActiveRecord
|
|
|
692
700
|
# method does nothing.
|
|
693
701
|
def disconnect!
|
|
694
702
|
@lock.synchronize do
|
|
703
|
+
@last_activity = nil
|
|
704
|
+
@verified = false
|
|
695
705
|
clear_cache!(new_connection: true)
|
|
696
706
|
reset_transaction
|
|
697
707
|
@raw_connection_dirty = false
|
|
@@ -717,9 +727,11 @@ module ActiveRecord
|
|
|
717
727
|
# should call super immediately after resetting the connection (and while
|
|
718
728
|
# still holding @lock).
|
|
719
729
|
def reset!
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
730
|
+
attempt_configure_connection do
|
|
731
|
+
clear_cache!(new_connection: true)
|
|
732
|
+
reset_transaction
|
|
733
|
+
configure_connection
|
|
734
|
+
end
|
|
723
735
|
end
|
|
724
736
|
|
|
725
737
|
# Removes the connection from the pool and disconnect it.
|
|
@@ -753,10 +765,13 @@ module ActiveRecord
|
|
|
753
765
|
unless active?
|
|
754
766
|
@lock.synchronize do
|
|
755
767
|
if @unconfigured_connection
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
768
|
+
attempt_configure_connection do
|
|
769
|
+
@raw_connection = @unconfigured_connection
|
|
770
|
+
@unconfigured_connection = nil
|
|
771
|
+
configure_connection
|
|
772
|
+
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
773
|
+
@verified = true
|
|
774
|
+
end
|
|
760
775
|
return
|
|
761
776
|
end
|
|
762
777
|
|
|
@@ -985,6 +1000,9 @@ module ActiveRecord
|
|
|
985
1000
|
if @verified
|
|
986
1001
|
# Cool, we're confident the connection's ready to use. (Note this might have
|
|
987
1002
|
# become true during the above #materialize_transactions.)
|
|
1003
|
+
elsif (last_activity = seconds_since_last_activity) && last_activity < verify_timeout
|
|
1004
|
+
# We haven't actually verified the connection since we acquired it, but it
|
|
1005
|
+
# has been used very recently. We're going to assume it's still okay.
|
|
988
1006
|
elsif reconnectable
|
|
989
1007
|
if allow_retry
|
|
990
1008
|
# Not sure about the connection yet, but if anything goes wrong we can
|
|
@@ -1026,6 +1044,7 @@ module ActiveRecord
|
|
|
1026
1044
|
# Barring a known-retryable error inside the query (regardless of
|
|
1027
1045
|
# whether we were in a _position_ to retry it), we should infer that
|
|
1028
1046
|
# there's likely a real problem with the connection.
|
|
1047
|
+
@last_activity = nil
|
|
1029
1048
|
@verified = false
|
|
1030
1049
|
end
|
|
1031
1050
|
|
|
@@ -1040,11 +1059,13 @@ module ActiveRecord
|
|
|
1040
1059
|
# `with_raw_connection` block only when the block is guaranteed to
|
|
1041
1060
|
# exercise the raw connection.
|
|
1042
1061
|
def verified!
|
|
1062
|
+
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
1043
1063
|
@verified = true
|
|
1044
1064
|
end
|
|
1045
1065
|
|
|
1046
1066
|
def retryable_connection_error?(exception)
|
|
1047
|
-
exception.is_a?(ConnectionNotEstablished)
|
|
1067
|
+
(exception.is_a?(ConnectionNotEstablished) && !exception.is_a?(ConnectionNotDefined)) ||
|
|
1068
|
+
exception.is_a?(ConnectionFailed)
|
|
1048
1069
|
end
|
|
1049
1070
|
|
|
1050
1071
|
def invalidate_transaction(exception)
|
|
@@ -1105,24 +1126,25 @@ module ActiveRecord
|
|
|
1105
1126
|
end
|
|
1106
1127
|
end
|
|
1107
1128
|
|
|
1108
|
-
def translate_exception_class(
|
|
1109
|
-
|
|
1129
|
+
def translate_exception_class(native_error, sql, binds)
|
|
1130
|
+
return native_error if native_error.is_a?(ActiveRecordError)
|
|
1110
1131
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1132
|
+
message = "#{native_error.class.name}: #{native_error.message}"
|
|
1133
|
+
|
|
1134
|
+
active_record_error = translate_exception(
|
|
1135
|
+
native_error, message: message, sql: sql, binds: binds
|
|
1113
1136
|
)
|
|
1114
|
-
|
|
1115
|
-
|
|
1137
|
+
active_record_error.set_backtrace(native_error.backtrace)
|
|
1138
|
+
active_record_error
|
|
1116
1139
|
end
|
|
1117
1140
|
|
|
1118
|
-
def log(sql, name = "SQL", binds = [], type_casted_binds = [],
|
|
1119
|
-
|
|
1141
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], async: false, &block) # :doc:
|
|
1142
|
+
instrumenter.instrument(
|
|
1120
1143
|
"sql.active_record",
|
|
1121
1144
|
sql: sql,
|
|
1122
1145
|
name: name,
|
|
1123
1146
|
binds: binds,
|
|
1124
1147
|
type_casted_binds: type_casted_binds,
|
|
1125
|
-
statement_name: statement_name,
|
|
1126
1148
|
async: async,
|
|
1127
1149
|
connection: self,
|
|
1128
1150
|
transaction: current_transaction.user_transaction.presence,
|
|
@@ -1133,11 +1155,8 @@ module ActiveRecord
|
|
|
1133
1155
|
raise ex.set_query(sql, binds)
|
|
1134
1156
|
end
|
|
1135
1157
|
|
|
1136
|
-
def
|
|
1137
|
-
|
|
1138
|
-
sql = transformer.call(sql, self)
|
|
1139
|
-
end
|
|
1140
|
-
sql
|
|
1158
|
+
def instrumenter # :nodoc:
|
|
1159
|
+
ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] ||= ActiveSupport::Notifications.instrumenter
|
|
1141
1160
|
end
|
|
1142
1161
|
|
|
1143
1162
|
def translate_exception(exception, message:, sql:, binds:)
|
|
@@ -1150,10 +1169,6 @@ module ActiveRecord
|
|
|
1150
1169
|
end
|
|
1151
1170
|
end
|
|
1152
1171
|
|
|
1153
|
-
def without_prepared_statement?(binds)
|
|
1154
|
-
!prepared_statements || binds.empty?
|
|
1155
|
-
end
|
|
1156
|
-
|
|
1157
1172
|
def column_for(table_name, column_name)
|
|
1158
1173
|
column_name = column_name.to_s
|
|
1159
1174
|
columns(table_name).detect { |c| c.name == column_name } ||
|
|
@@ -1205,6 +1220,13 @@ module ActiveRecord
|
|
|
1205
1220
|
check_version
|
|
1206
1221
|
end
|
|
1207
1222
|
|
|
1223
|
+
def attempt_configure_connection
|
|
1224
|
+
yield
|
|
1225
|
+
rescue Exception # Need to handle things such as Timeout::ExitException
|
|
1226
|
+
disconnect!
|
|
1227
|
+
raise
|
|
1228
|
+
end
|
|
1229
|
+
|
|
1208
1230
|
def default_prepared_statements
|
|
1209
1231
|
true
|
|
1210
1232
|
end
|