activerecord 7.2.3.1 → 8.0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +475 -946
- data/README.rdoc +1 -1
- data/lib/active_record/association_relation.rb +1 -0
- data/lib/active_record/associations/association.rb +34 -10
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/collection_association.rb +1 -1
- 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.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/time_zone_conversion.rb +2 -12
- data/lib/active_record/autosave_association.rb +69 -27
- 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 +8 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +91 -44
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -2
- 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 +7 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +37 -10
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +67 -74
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +21 -40
- data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
- 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 +1 -8
- 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 +6 -12
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +59 -16
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +53 -96
- 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/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 +9 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +53 -12
- 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 +0 -17
- data/lib/active_record/connection_adapters.rb +0 -56
- data/lib/active_record/connection_handling.rb +23 -1
- data/lib/active_record/core.rb +29 -14
- 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/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +4 -4
- data/lib/active_record/encryption/encrypted_attribute_type.rb +10 -1
- data/lib/active_record/encryption/encryptor.rb +16 -8
- 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 +9 -22
- data/lib/active_record/errors.rb +13 -5
- data/lib/active_record/fixtures.rb +0 -2
- data/lib/active_record/future_result.rb +15 -9
- data/lib/active_record/gem_version.rb +3 -3
- 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 +38 -42
- 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 +102 -50
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +8 -8
- data/lib/active_record/railtie.rb +2 -26
- data/lib/active_record/railties/databases.rake +11 -35
- 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 +40 -39
- data/lib/active_record/relation/delegation.rb +25 -14
- data/lib/active_record/relation/finder_methods.rb +18 -18
- 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/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_methods.rb +105 -61
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +1 -1
- data/lib/active_record/relation.rb +80 -62
- data/lib/active_record/result.rb +66 -4
- data/lib/active_record/sanitization.rb +7 -6
- data/lib/active_record/schema_dumper.rb +5 -0
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- 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 +2 -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 +5 -6
- data/lib/active_record/type/serialized.rb +5 -0
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +21 -48
- 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/nodes/binary.rb +1 -1
- data/lib/arel/nodes/node.rb +1 -1
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/predications.rb +1 -3
- data/lib/arel/table.rb +3 -7
- metadata +10 -11
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
|
@@ -28,6 +28,7 @@ module ActiveRecord
|
|
|
28
28
|
sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
|
|
29
29
|
sql << o.check_constraint_adds.map { |con| visit_AddCheckConstraint con }.join(" ")
|
|
30
30
|
sql << o.check_constraint_drops.map { |con| visit_DropCheckConstraint con }.join(" ")
|
|
31
|
+
sql << o.constraint_drops.map { |con| visit_DropConstraint con }.join(" ")
|
|
31
32
|
end
|
|
32
33
|
|
|
33
34
|
def visit_ColumnDefinition(o)
|
|
@@ -96,9 +97,11 @@ module ActiveRecord
|
|
|
96
97
|
"ADD #{accept(o)}"
|
|
97
98
|
end
|
|
98
99
|
|
|
99
|
-
def
|
|
100
|
+
def visit_DropConstraint(name)
|
|
100
101
|
"DROP CONSTRAINT #{quote_column_name(name)}"
|
|
101
102
|
end
|
|
103
|
+
alias :visit_DropForeignKey :visit_DropConstraint
|
|
104
|
+
alias :visit_DropCheckConstraint :visit_DropConstraint
|
|
102
105
|
|
|
103
106
|
def visit_CreateIndexDefinition(o)
|
|
104
107
|
index = o.index
|
|
@@ -127,10 +130,6 @@ module ActiveRecord
|
|
|
127
130
|
"ADD #{accept(o)}"
|
|
128
131
|
end
|
|
129
132
|
|
|
130
|
-
def visit_DropCheckConstraint(name)
|
|
131
|
-
"DROP CONSTRAINT #{quote_column_name(name)}"
|
|
132
|
-
end
|
|
133
|
-
|
|
134
133
|
def quoted_columns(o)
|
|
135
134
|
String === o.columns ? o.columns : quoted_columns_for_index(o.columns, o.column_options)
|
|
136
135
|
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
module ActiveRecord
|
|
5
4
|
module ConnectionAdapters # :nodoc:
|
|
6
5
|
# Abstract representation of an index definition on a table. Instances of
|
|
@@ -352,7 +351,7 @@ module ActiveRecord
|
|
|
352
351
|
# Inside migration files, the +t+ object in {create_table}[rdoc-ref:SchemaStatements#create_table]
|
|
353
352
|
# is actually of this type:
|
|
354
353
|
#
|
|
355
|
-
# class SomeMigration < ActiveRecord::Migration[
|
|
354
|
+
# class SomeMigration < ActiveRecord::Migration[8.0]
|
|
356
355
|
# def up
|
|
357
356
|
# create_table :foo do |t|
|
|
358
357
|
# puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
|
|
@@ -626,6 +625,7 @@ module ActiveRecord
|
|
|
626
625
|
attr_reader :adds
|
|
627
626
|
attr_reader :foreign_key_adds, :foreign_key_drops
|
|
628
627
|
attr_reader :check_constraint_adds, :check_constraint_drops
|
|
628
|
+
attr_reader :constraint_drops
|
|
629
629
|
|
|
630
630
|
def initialize(td)
|
|
631
631
|
@td = td
|
|
@@ -634,6 +634,7 @@ module ActiveRecord
|
|
|
634
634
|
@foreign_key_drops = []
|
|
635
635
|
@check_constraint_adds = []
|
|
636
636
|
@check_constraint_drops = []
|
|
637
|
+
@constraint_drops = []
|
|
637
638
|
end
|
|
638
639
|
|
|
639
640
|
def name; @td.name; end
|
|
@@ -654,6 +655,10 @@ module ActiveRecord
|
|
|
654
655
|
@check_constraint_drops << constraint_name
|
|
655
656
|
end
|
|
656
657
|
|
|
658
|
+
def drop_constraint(constraint_name)
|
|
659
|
+
@constraint_drops << constraint_name
|
|
660
|
+
end
|
|
661
|
+
|
|
657
662
|
def add_column(name, type, **options)
|
|
658
663
|
name = name.to_s
|
|
659
664
|
type = type.to_sym
|
|
@@ -348,6 +348,15 @@ module ActiveRecord
|
|
|
348
348
|
# # Creates a table called 'assemblies_parts' with no id.
|
|
349
349
|
# create_join_table(:assemblies, :parts)
|
|
350
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
|
+
#
|
|
351
360
|
# You can pass an +options+ hash which can include the following keys:
|
|
352
361
|
# [<tt>:table_name</tt>]
|
|
353
362
|
# Sets the table name, overriding the default.
|
|
@@ -519,7 +528,7 @@ module ActiveRecord
|
|
|
519
528
|
raise NotImplementedError, "rename_table is not implemented"
|
|
520
529
|
end
|
|
521
530
|
|
|
522
|
-
# Drops a table from the database.
|
|
531
|
+
# Drops a table or tables from the database.
|
|
523
532
|
#
|
|
524
533
|
# [<tt>:force</tt>]
|
|
525
534
|
# Set to +:cascade+ to drop dependent objects as well.
|
|
@@ -530,17 +539,19 @@ module ActiveRecord
|
|
|
530
539
|
#
|
|
531
540
|
# Although this command ignores most +options+ and the block if one is given,
|
|
532
541
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
|
533
|
-
# In that case, +options+ and the block will be used by #create_table.
|
|
534
|
-
def drop_table(
|
|
535
|
-
|
|
536
|
-
|
|
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
|
|
537
548
|
end
|
|
538
549
|
|
|
539
550
|
# Add a new +type+ column named +column_name+ to +table_name+.
|
|
540
551
|
#
|
|
541
552
|
# See {ActiveRecord::ConnectionAdapters::TableDefinition.column}[rdoc-ref:ActiveRecord::ConnectionAdapters::TableDefinition#column].
|
|
542
553
|
#
|
|
543
|
-
# The +type+ parameter is normally one of the
|
|
554
|
+
# The +type+ parameter is normally one of the migration's native types,
|
|
544
555
|
# which is one of the following:
|
|
545
556
|
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
|
|
546
557
|
# <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:numeric</tt>,
|
|
@@ -847,6 +858,16 @@ module ActiveRecord
|
|
|
847
858
|
#
|
|
848
859
|
# Note: only supported by PostgreSQL.
|
|
849
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
|
+
#
|
|
850
871
|
# ====== Creating an index with a specific method
|
|
851
872
|
#
|
|
852
873
|
# add_index(:developers, :name, using: 'btree')
|
|
@@ -1316,7 +1337,6 @@ module ActiveRecord
|
|
|
1316
1337
|
execute schema_creation.accept(at)
|
|
1317
1338
|
end
|
|
1318
1339
|
|
|
1319
|
-
|
|
1320
1340
|
# Checks to see if a check constraint exists on a table for a given check constraint definition.
|
|
1321
1341
|
#
|
|
1322
1342
|
# check_constraint_exists?(:products, name: "price_check")
|
|
@@ -1328,6 +1348,13 @@ module ActiveRecord
|
|
|
1328
1348
|
check_constraint_for(table_name, **options).present?
|
|
1329
1349
|
end
|
|
1330
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
|
+
|
|
1331
1358
|
def dump_schema_information # :nodoc:
|
|
1332
1359
|
versions = pool.schema_migration.versions
|
|
1333
1360
|
insert_versions_sql(versions) if versions.any?
|
|
@@ -1533,11 +1560,11 @@ module ActiveRecord
|
|
|
1533
1560
|
non_combinable_operations = []
|
|
1534
1561
|
|
|
1535
1562
|
operations.each do |command, args|
|
|
1536
|
-
|
|
1563
|
+
args.shift # remove table_name
|
|
1537
1564
|
method = :"#{command}_for_alter"
|
|
1538
1565
|
|
|
1539
1566
|
if respond_to?(method, true)
|
|
1540
|
-
sqls, procs = Array(send(method,
|
|
1567
|
+
sqls, procs = Array(send(method, table_name, *args)).partition { |v| v.is_a?(String) }
|
|
1541
1568
|
sql_fragments.concat(sqls)
|
|
1542
1569
|
non_combinable_operations.concat(procs)
|
|
1543
1570
|
else
|
|
@@ -1545,7 +1572,7 @@ module ActiveRecord
|
|
|
1545
1572
|
non_combinable_operations.each(&:call)
|
|
1546
1573
|
sql_fragments = []
|
|
1547
1574
|
non_combinable_operations = []
|
|
1548
|
-
send(command,
|
|
1575
|
+
send(command, table_name, *args)
|
|
1549
1576
|
end
|
|
1550
1577
|
end
|
|
1551
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"
|
|
@@ -153,7 +152,6 @@ module ActiveRecord
|
|
|
153
152
|
|
|
154
153
|
@owner = nil
|
|
155
154
|
@pinned = false
|
|
156
|
-
@instrumenter = ActiveSupport::Notifications.instrumenter
|
|
157
155
|
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
|
158
156
|
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
159
157
|
@visitor = arel_visitor
|
|
@@ -194,19 +192,6 @@ module ActiveRecord
|
|
|
194
192
|
end
|
|
195
193
|
end
|
|
196
194
|
|
|
197
|
-
EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
|
|
198
|
-
EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze # :nodoc:
|
|
199
|
-
private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
|
|
200
|
-
def with_instrumenter(instrumenter, &block) # :nodoc:
|
|
201
|
-
Thread.handle_interrupt(EXCEPTION_NEVER) do
|
|
202
|
-
previous_instrumenter = @instrumenter
|
|
203
|
-
@instrumenter = instrumenter
|
|
204
|
-
Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
|
|
205
|
-
ensure
|
|
206
|
-
@instrumenter = previous_instrumenter
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
|
|
210
195
|
def check_if_write_query(sql) # :nodoc:
|
|
211
196
|
if preventing_writes? && write_query?(sql)
|
|
212
197
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
|
@@ -243,9 +228,9 @@ module ActiveRecord
|
|
|
243
228
|
# the value of +current_preventing_writes+.
|
|
244
229
|
def preventing_writes?
|
|
245
230
|
return true if replica?
|
|
246
|
-
return false if
|
|
231
|
+
return false if connection_descriptor.nil?
|
|
247
232
|
|
|
248
|
-
|
|
233
|
+
connection_descriptor.current_preventing_writes
|
|
249
234
|
end
|
|
250
235
|
|
|
251
236
|
def prepared_statements?
|
|
@@ -296,8 +281,8 @@ module ActiveRecord
|
|
|
296
281
|
@owner = ActiveSupport::IsolatedExecutionState.context
|
|
297
282
|
end
|
|
298
283
|
|
|
299
|
-
def
|
|
300
|
-
@pool.
|
|
284
|
+
def connection_descriptor # :nodoc:
|
|
285
|
+
@pool.connection_descriptor
|
|
301
286
|
end
|
|
302
287
|
|
|
303
288
|
# The role (e.g. +:writing+) for the current connection. In a
|
|
@@ -590,23 +575,31 @@ module ActiveRecord
|
|
|
590
575
|
end
|
|
591
576
|
|
|
592
577
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
593
|
-
def create_enum(
|
|
578
|
+
def create_enum(...) # :nodoc:
|
|
594
579
|
end
|
|
595
580
|
|
|
596
581
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
597
|
-
def drop_enum(
|
|
582
|
+
def drop_enum(...) # :nodoc:
|
|
598
583
|
end
|
|
599
584
|
|
|
600
585
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
601
|
-
def rename_enum(
|
|
586
|
+
def rename_enum(...) # :nodoc:
|
|
602
587
|
end
|
|
603
588
|
|
|
604
589
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
605
|
-
def add_enum_value(
|
|
590
|
+
def add_enum_value(...) # :nodoc:
|
|
606
591
|
end
|
|
607
592
|
|
|
608
593
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
609
|
-
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:
|
|
610
603
|
end
|
|
611
604
|
|
|
612
605
|
def advisory_locks_enabled? # :nodoc:
|
|
@@ -673,34 +666,33 @@ module ActiveRecord
|
|
|
673
666
|
deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline
|
|
674
667
|
|
|
675
668
|
@lock.synchronize do
|
|
676
|
-
|
|
669
|
+
attempt_configure_connection do
|
|
670
|
+
reconnect
|
|
677
671
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
672
|
+
enable_lazy_transactions!
|
|
673
|
+
@raw_connection_dirty = false
|
|
674
|
+
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
675
|
+
@verified = true
|
|
682
676
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
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)
|
|
690
684
|
|
|
691
|
-
|
|
692
|
-
|
|
685
|
+
if !retry_deadline_exceeded && retries_available > 0
|
|
686
|
+
retries_available -= 1
|
|
693
687
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
688
|
+
if retryable_connection_error?(translated_exception)
|
|
689
|
+
backoff(connection_retries - retries_available)
|
|
690
|
+
retry
|
|
691
|
+
end
|
|
697
692
|
end
|
|
698
|
-
end
|
|
699
|
-
|
|
700
|
-
@last_activity = nil
|
|
701
|
-
@verified = false
|
|
702
693
|
|
|
703
|
-
|
|
694
|
+
raise translated_exception
|
|
695
|
+
end
|
|
704
696
|
end
|
|
705
697
|
end
|
|
706
698
|
|
|
@@ -708,6 +700,8 @@ module ActiveRecord
|
|
|
708
700
|
# method does nothing.
|
|
709
701
|
def disconnect!
|
|
710
702
|
@lock.synchronize do
|
|
703
|
+
@last_activity = nil
|
|
704
|
+
@verified = false
|
|
711
705
|
clear_cache!(new_connection: true)
|
|
712
706
|
reset_transaction
|
|
713
707
|
@raw_connection_dirty = false
|
|
@@ -733,9 +727,11 @@ module ActiveRecord
|
|
|
733
727
|
# should call super immediately after resetting the connection (and while
|
|
734
728
|
# still holding @lock).
|
|
735
729
|
def reset!
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
730
|
+
attempt_configure_connection do
|
|
731
|
+
clear_cache!(new_connection: true)
|
|
732
|
+
reset_transaction
|
|
733
|
+
configure_connection
|
|
734
|
+
end
|
|
739
735
|
end
|
|
740
736
|
|
|
741
737
|
# Removes the connection from the pool and disconnect it.
|
|
@@ -769,11 +765,13 @@ module ActiveRecord
|
|
|
769
765
|
unless active?
|
|
770
766
|
@lock.synchronize do
|
|
771
767
|
if @unconfigured_connection
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
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
|
|
777
775
|
return
|
|
778
776
|
end
|
|
779
777
|
|
|
@@ -1066,7 +1064,8 @@ module ActiveRecord
|
|
|
1066
1064
|
end
|
|
1067
1065
|
|
|
1068
1066
|
def retryable_connection_error?(exception)
|
|
1069
|
-
exception.is_a?(ConnectionNotEstablished)
|
|
1067
|
+
(exception.is_a?(ConnectionNotEstablished) && !exception.is_a?(ConnectionNotDefined)) ||
|
|
1068
|
+
exception.is_a?(ConnectionFailed)
|
|
1070
1069
|
end
|
|
1071
1070
|
|
|
1072
1071
|
def invalidate_transaction(exception)
|
|
@@ -1127,24 +1126,25 @@ module ActiveRecord
|
|
|
1127
1126
|
end
|
|
1128
1127
|
end
|
|
1129
1128
|
|
|
1130
|
-
def translate_exception_class(
|
|
1131
|
-
|
|
1129
|
+
def translate_exception_class(native_error, sql, binds)
|
|
1130
|
+
return native_error if native_error.is_a?(ActiveRecordError)
|
|
1132
1131
|
|
|
1133
|
-
|
|
1134
|
-
|
|
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
|
|
1135
1136
|
)
|
|
1136
|
-
|
|
1137
|
-
|
|
1137
|
+
active_record_error.set_backtrace(native_error.backtrace)
|
|
1138
|
+
active_record_error
|
|
1138
1139
|
end
|
|
1139
1140
|
|
|
1140
|
-
def log(sql, name = "SQL", binds = [], type_casted_binds = [],
|
|
1141
|
-
|
|
1141
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], async: false, &block) # :doc:
|
|
1142
|
+
instrumenter.instrument(
|
|
1142
1143
|
"sql.active_record",
|
|
1143
1144
|
sql: sql,
|
|
1144
1145
|
name: name,
|
|
1145
1146
|
binds: binds,
|
|
1146
1147
|
type_casted_binds: type_casted_binds,
|
|
1147
|
-
statement_name: statement_name,
|
|
1148
1148
|
async: async,
|
|
1149
1149
|
connection: self,
|
|
1150
1150
|
transaction: current_transaction.user_transaction.presence,
|
|
@@ -1155,11 +1155,8 @@ module ActiveRecord
|
|
|
1155
1155
|
raise ex.set_query(sql, binds)
|
|
1156
1156
|
end
|
|
1157
1157
|
|
|
1158
|
-
def
|
|
1159
|
-
|
|
1160
|
-
sql = transformer.call(sql, self)
|
|
1161
|
-
end
|
|
1162
|
-
sql
|
|
1158
|
+
def instrumenter # :nodoc:
|
|
1159
|
+
ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] ||= ActiveSupport::Notifications.instrumenter
|
|
1163
1160
|
end
|
|
1164
1161
|
|
|
1165
1162
|
def translate_exception(exception, message:, sql:, binds:)
|
|
@@ -1172,10 +1169,6 @@ module ActiveRecord
|
|
|
1172
1169
|
end
|
|
1173
1170
|
end
|
|
1174
1171
|
|
|
1175
|
-
def without_prepared_statement?(binds)
|
|
1176
|
-
!prepared_statements || binds.empty?
|
|
1177
|
-
end
|
|
1178
|
-
|
|
1179
1172
|
def column_for(table_name, column_name)
|
|
1180
1173
|
column_name = column_name.to_s
|
|
1181
1174
|
columns(table_name).detect { |c| c.name == column_name } ||
|
|
@@ -1228,7 +1221,7 @@ module ActiveRecord
|
|
|
1228
1221
|
end
|
|
1229
1222
|
|
|
1230
1223
|
def attempt_configure_connection
|
|
1231
|
-
|
|
1224
|
+
yield
|
|
1232
1225
|
rescue Exception # Need to handle things such as Timeout::ExitException
|
|
1233
1226
|
disconnect!
|
|
1234
1227
|
raise
|
|
@@ -79,7 +79,7 @@ module ActiveRecord
|
|
|
79
79
|
|
|
80
80
|
args << config.database
|
|
81
81
|
|
|
82
|
-
find_cmd_and_exec([
|
|
82
|
+
find_cmd_and_exec(ActiveRecord.database_cli[:mysql], *args)
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
|
|
@@ -98,7 +98,7 @@ module ActiveRecord
|
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
def supports_index_sort_order?
|
|
101
|
-
|
|
101
|
+
mariadb? ? database_version >= "10.8.1" : database_version >= "8.0.1"
|
|
102
102
|
end
|
|
103
103
|
|
|
104
104
|
def supports_expression_index?
|
|
@@ -138,7 +138,7 @@ module ActiveRecord
|
|
|
138
138
|
end
|
|
139
139
|
|
|
140
140
|
def supports_datetime_with_precision?
|
|
141
|
-
|
|
141
|
+
true
|
|
142
142
|
end
|
|
143
143
|
|
|
144
144
|
def supports_virtual_columns?
|
|
@@ -201,12 +201,6 @@ module ActiveRecord
|
|
|
201
201
|
|
|
202
202
|
# HELPER METHODS ===========================================
|
|
203
203
|
|
|
204
|
-
# The two drivers have slightly different ways of yielding hashes of results, so
|
|
205
|
-
# this method must be implemented to provide a uniform interface.
|
|
206
|
-
def each_hash(result) # :nodoc:
|
|
207
|
-
raise NotImplementedError
|
|
208
|
-
end
|
|
209
|
-
|
|
210
204
|
# Must return the MySQL error number from the exception, if the exception has an
|
|
211
205
|
# error number.
|
|
212
206
|
def error_number(exception) # :nodoc:
|
|
@@ -230,24 +224,19 @@ module ActiveRecord
|
|
|
230
224
|
# DATABASE STATEMENTS ======================================
|
|
231
225
|
#++
|
|
232
226
|
|
|
233
|
-
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
|
234
|
-
# to write stuff in an abstract way without concerning ourselves about whether it
|
|
235
|
-
# needs to be explicitly freed or not.
|
|
236
|
-
def execute_and_free(sql, name = nil, async: false, allow_retry: false) # :nodoc:
|
|
237
|
-
sql = transform_query(sql)
|
|
238
|
-
check_if_write_query(sql)
|
|
239
|
-
|
|
240
|
-
mark_transaction_written_if_write(sql)
|
|
241
|
-
yield raw_execute(sql, name, async: async, allow_retry: allow_retry)
|
|
242
|
-
end
|
|
243
|
-
|
|
244
227
|
def begin_db_transaction # :nodoc:
|
|
245
228
|
internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
246
229
|
end
|
|
247
230
|
|
|
248
231
|
def begin_isolated_db_transaction(isolation) # :nodoc:
|
|
249
|
-
|
|
250
|
-
|
|
232
|
+
# From MySQL manual: The [SET TRANSACTION] statement applies only to the next single transaction performed within the session.
|
|
233
|
+
# So we don't need to implement #reset_isolation_level
|
|
234
|
+
execute_batch(
|
|
235
|
+
["SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "BEGIN"],
|
|
236
|
+
"TRANSACTION",
|
|
237
|
+
allow_retry: true,
|
|
238
|
+
materialize_transactions: false,
|
|
239
|
+
)
|
|
251
240
|
end
|
|
252
241
|
|
|
253
242
|
def commit_db_transaction # :nodoc:
|
|
@@ -347,7 +336,7 @@ module ActiveRecord
|
|
|
347
336
|
rename_table_indexes(table_name, new_name, **options)
|
|
348
337
|
end
|
|
349
338
|
|
|
350
|
-
# Drops a table from the database.
|
|
339
|
+
# Drops a table or tables from the database.
|
|
351
340
|
#
|
|
352
341
|
# [<tt>:force</tt>]
|
|
353
342
|
# Set to +:cascade+ to drop dependent objects as well.
|
|
@@ -361,10 +350,10 @@ module ActiveRecord
|
|
|
361
350
|
#
|
|
362
351
|
# Although this command ignores most +options+ and the block if one is given,
|
|
363
352
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
|
364
|
-
# In that case, +options+ and the block will be used by create_table.
|
|
365
|
-
def drop_table(
|
|
366
|
-
schema_cache.clear_data_source_cache!(table_name.to_s)
|
|
367
|
-
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
|
|
353
|
+
# 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.
|
|
354
|
+
def drop_table(*table_names, **options)
|
|
355
|
+
table_names.each { |table_name| schema_cache.clear_data_source_cache!(table_name.to_s) }
|
|
356
|
+
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{table_names.map { |table_name| quote_table_name(table_name) }.join(', ')}#{' CASCADE' if options[:force] == :cascade}"
|
|
368
357
|
end
|
|
369
358
|
|
|
370
359
|
def rename_index(table_name, old_name, new_name)
|
|
@@ -588,7 +577,7 @@ module ActiveRecord
|
|
|
588
577
|
|
|
589
578
|
# SHOW VARIABLES LIKE 'name'
|
|
590
579
|
def show_variable(name)
|
|
591
|
-
query_value("SELECT @@#{name}", "SCHEMA")
|
|
580
|
+
query_value("SELECT @@#{name}", "SCHEMA", materialize_transactions: false, allow_retry: true)
|
|
592
581
|
rescue ActiveRecord::StatementInvalid
|
|
593
582
|
nil
|
|
594
583
|
end
|
|
@@ -693,8 +682,8 @@ module ActiveRecord
|
|
|
693
682
|
end
|
|
694
683
|
|
|
695
684
|
def check_version # :nodoc:
|
|
696
|
-
if database_version < "5.
|
|
697
|
-
raise DatabaseVersionError, "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.
|
|
685
|
+
if database_version < "5.6.4"
|
|
686
|
+
raise DatabaseVersionError, "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.6.4."
|
|
698
687
|
end
|
|
699
688
|
end
|
|
700
689
|
|
|
@@ -781,7 +770,6 @@ module ActiveRecord
|
|
|
781
770
|
def handle_warnings(sql)
|
|
782
771
|
return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
|
|
783
772
|
|
|
784
|
-
@affected_rows_before_warnings = @raw_connection.affected_rows
|
|
785
773
|
warning_count = @raw_connection.warning_count
|
|
786
774
|
result = @raw_connection.query("SHOW WARNINGS")
|
|
787
775
|
result = [
|
|
@@ -799,11 +787,6 @@ module ActiveRecord
|
|
|
799
787
|
warning.level == "Note" || super
|
|
800
788
|
end
|
|
801
789
|
|
|
802
|
-
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
|
803
|
-
# made since we established the connection
|
|
804
|
-
def sync_timezone_changes(raw_connection)
|
|
805
|
-
end
|
|
806
|
-
|
|
807
790
|
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
|
|
808
791
|
ER_DB_CREATE_EXISTS = 1007
|
|
809
792
|
ER_FILSORT_ABORT = 1028
|
|
@@ -973,13 +956,11 @@ module ActiveRecord
|
|
|
973
956
|
end.join(", ")
|
|
974
957
|
|
|
975
958
|
# ...and send them all in one query
|
|
976
|
-
|
|
959
|
+
raw_execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
|
977
960
|
end
|
|
978
961
|
|
|
979
962
|
def column_definitions(table_name) # :nodoc:
|
|
980
|
-
|
|
981
|
-
each_hash(result)
|
|
982
|
-
end
|
|
963
|
+
internal_exec_query("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", "SCHEMA")
|
|
983
964
|
end
|
|
984
965
|
|
|
985
966
|
def create_table_info(table_name) # :nodoc:
|
|
@@ -42,18 +42,12 @@ module ActiveRecord
|
|
|
42
42
|
# :method: unsigned_bigint
|
|
43
43
|
# :call-seq: unsigned_bigint(*names, **options)
|
|
44
44
|
|
|
45
|
-
##
|
|
46
|
-
# :method: unsigned_float
|
|
47
|
-
# :call-seq: unsigned_float(*names, **options)
|
|
48
|
-
|
|
49
|
-
##
|
|
50
|
-
# :method: unsigned_decimal
|
|
51
|
-
# :call-seq: unsigned_decimal(*names, **options)
|
|
52
|
-
|
|
53
45
|
included do
|
|
54
46
|
define_column_methods :blob, :tinyblob, :mediumblob, :longblob,
|
|
55
47
|
:tinytext, :mediumtext, :longtext, :unsigned_integer, :unsigned_bigint,
|
|
56
48
|
:unsigned_float, :unsigned_decimal
|
|
49
|
+
|
|
50
|
+
deprecate :unsigned_float, :unsigned_decimal, deprecator: ActiveRecord.deprecator
|
|
57
51
|
end
|
|
58
52
|
end
|
|
59
53
|
|