activerecord 6.1.4 → 7.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1049 -977
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +33 -17
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +15 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +34 -27
- data/lib/active_record/associations/collection_proxy.rb +8 -3
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/preloader/association.rb +187 -55
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +49 -13
- data/lib/active_record/associations/preloader.rb +39 -113
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +90 -82
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +49 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +7 -5
- data/lib/active_record/attribute_methods/serialization.rb +66 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +13 -14
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +6 -21
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +34 -9
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +69 -18
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +97 -81
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +35 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +35 -21
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +4 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +50 -50
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +27 -16
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +205 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +29 -4
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +15 -16
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +47 -53
- data/lib/active_record/core.rb +122 -132
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -9
- data/lib/active_record/database_configurations/hash_config.rb +63 -5
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +16 -32
- data/lib/active_record/delegated_type.rb +52 -11
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +61 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +208 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +90 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +49 -42
- data/lib/active_record/errors.rb +67 -4
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +41 -6
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +17 -20
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +80 -14
- data/lib/active_record/integration.rb +4 -3
- data/lib/active_record/internal_metadata.rb +3 -5
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/locking/pessimistic.rb +9 -3
- data/lib/active_record/log_subscriber.rb +14 -3
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +8 -3
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +83 -1
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +109 -79
- data/lib/active_record/model_schema.rb +45 -58
- data/lib/active_record/nested_attributes.rb +13 -12
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +219 -52
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +138 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +127 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +66 -129
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +67 -50
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +40 -36
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +31 -35
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +235 -61
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +171 -84
- data/lib/active_record/result.rb +17 -7
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +10 -3
- data/lib/active_record/schema_migration.rb +0 -4
- data/lib/active_record/scoping/default.rb +61 -12
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +116 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -12
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +4 -4
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +2 -2
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +1 -1
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +1 -1
- data/lib/active_record.rb +204 -28
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +11 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +8 -2
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +58 -2
- data/lib/arel.rb +2 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- metadata +56 -13
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/string/access"
|
4
|
-
require "
|
4
|
+
require "openssl"
|
5
5
|
|
6
6
|
module ActiveRecord
|
7
7
|
module ConnectionAdapters # :nodoc:
|
@@ -29,7 +29,7 @@ module ActiveRecord
|
|
29
29
|
table_name[0...table_alias_length].tr(".", "_")
|
30
30
|
end
|
31
31
|
|
32
|
-
# Returns the relation names
|
32
|
+
# Returns the relation names usable to back Active Record models.
|
33
33
|
# For most adapters this means all #tables and #views.
|
34
34
|
def data_sources
|
35
35
|
query_values(data_source_sql, "SCHEMA")
|
@@ -124,6 +124,9 @@ module ActiveRecord
|
|
124
124
|
# column_exists?(:suppliers, :name)
|
125
125
|
#
|
126
126
|
# # Check a column exists of a particular type
|
127
|
+
# #
|
128
|
+
# # This works for standard non-casted types (eg. string) but is unreliable
|
129
|
+
# # for types that may get cast to something else (eg. char, bigint).
|
127
130
|
# column_exists?(:suppliers, :name, :string)
|
128
131
|
#
|
129
132
|
# # Check a column exists with a specific definition
|
@@ -518,24 +521,31 @@ module ActiveRecord
|
|
518
521
|
|
519
522
|
# Add a new +type+ column named +column_name+ to +table_name+.
|
520
523
|
#
|
524
|
+
# See {ActiveRecord::ConnectionAdapters::TableDefinition.column}[rdoc-ref:ActiveRecord::ConnectionAdapters::TableDefinition#column].
|
525
|
+
#
|
521
526
|
# The +type+ parameter is normally one of the migrations native types,
|
522
527
|
# which is one of the following:
|
523
528
|
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
|
524
529
|
# <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:numeric</tt>,
|
525
530
|
# <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
|
526
|
-
# <tt>:binary</tt>, <tt>:boolean</tt>.
|
531
|
+
# <tt>:binary</tt>, <tt>:blob</tt>, <tt>:boolean</tt>.
|
527
532
|
#
|
528
533
|
# You may use a type not in this list as long as it is supported by your
|
529
534
|
# database (for example, "polygon" in MySQL), but this will not be database
|
530
535
|
# agnostic and should usually be avoided.
|
531
536
|
#
|
532
537
|
# Available options are (none of these exists by default):
|
538
|
+
# * <tt>:comment</tt> -
|
539
|
+
# Specifies the comment for the column. This option is ignored by some backends.
|
540
|
+
# * <tt>:collation</tt> -
|
541
|
+
# Specifies the collation for a <tt>:string</tt> or <tt>:text</tt> column.
|
542
|
+
# If not specified, the column will have the same collation as the table.
|
543
|
+
# * <tt>:default</tt> -
|
544
|
+
# The column's default value. Use +nil+ for +NULL+.
|
533
545
|
# * <tt>:limit</tt> -
|
534
546
|
# Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
|
535
|
-
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, and <tt>:integer</tt> columns.
|
547
|
+
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, <tt>:blob</tt>, and <tt>:integer</tt> columns.
|
536
548
|
# This option is ignored by some backends.
|
537
|
-
# * <tt>:default</tt> -
|
538
|
-
# The column's default value. Use +nil+ for +NULL+.
|
539
549
|
# * <tt>:null</tt> -
|
540
550
|
# Allows or disallows +NULL+ values in the column.
|
541
551
|
# * <tt>:precision</tt> -
|
@@ -604,7 +614,13 @@ module ActiveRecord
|
|
604
614
|
# # Ignores the method call if the column exists
|
605
615
|
# add_column(:shapes, :triangle, 'polygon', if_not_exists: true)
|
606
616
|
def add_column(table_name, column_name, type, **options)
|
607
|
-
return if options[:if_not_exists] == true && column_exists?(table_name, column_name
|
617
|
+
return if options[:if_not_exists] == true && column_exists?(table_name, column_name)
|
618
|
+
|
619
|
+
if supports_datetime_with_precision?
|
620
|
+
if type == :datetime && !options.key?(:precision)
|
621
|
+
options[:precision] = 6
|
622
|
+
end
|
623
|
+
end
|
608
624
|
|
609
625
|
at = create_alter_table table_name
|
610
626
|
at.add_column(column_name, type, **options)
|
@@ -629,9 +645,8 @@ module ActiveRecord
|
|
629
645
|
raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)")
|
630
646
|
end
|
631
647
|
|
632
|
-
column_names
|
633
|
-
|
634
|
-
end
|
648
|
+
remove_column_fragments = remove_columns_for_alter(table_name, *column_names, type: type, **options)
|
649
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{remove_column_fragments.join(', ')}"
|
635
650
|
end
|
636
651
|
|
637
652
|
# Removes the column from the table definition.
|
@@ -641,7 +656,8 @@ module ActiveRecord
|
|
641
656
|
# The +type+ and +options+ parameters will be ignored if present. It can be helpful
|
642
657
|
# to provide these in a migration's +change+ method so it can be reverted.
|
643
658
|
# In that case, +type+ and +options+ will be used by #add_column.
|
644
|
-
#
|
659
|
+
# Depending on the database you're using, indexes using this column may be
|
660
|
+
# automatically removed or modified to remove this column from the index.
|
645
661
|
#
|
646
662
|
# If the options provided include an +if_exists+ key, it will be used to check if the
|
647
663
|
# column does not exist. This will silently ignore the migration rather than raising
|
@@ -766,7 +782,7 @@ module ActiveRecord
|
|
766
782
|
#
|
767
783
|
# CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
|
768
784
|
#
|
769
|
-
# Note:
|
785
|
+
# Note: only supported by MySQL
|
770
786
|
#
|
771
787
|
# ====== Creating an index with a sort order (desc or asc, asc is the default)
|
772
788
|
#
|
@@ -901,7 +917,7 @@ module ActiveRecord
|
|
901
917
|
remove_index(table_name, name: old_name)
|
902
918
|
end
|
903
919
|
|
904
|
-
def index_name(table_name, options)
|
920
|
+
def index_name(table_name, options) # :nodoc:
|
905
921
|
if Hash === options
|
906
922
|
if options[:column]
|
907
923
|
"index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
|
@@ -1027,6 +1043,10 @@ module ActiveRecord
|
|
1027
1043
|
#
|
1028
1044
|
# ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
|
1029
1045
|
#
|
1046
|
+
# ====== Creating a foreign key, ignoring method call if the foreign key exists
|
1047
|
+
#
|
1048
|
+
# add_foreign_key(:articles, :authors, if_not_exists: true)
|
1049
|
+
#
|
1030
1050
|
# ====== Creating a foreign key on a specific column
|
1031
1051
|
#
|
1032
1052
|
# add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
|
@@ -1054,10 +1074,17 @@ module ActiveRecord
|
|
1054
1074
|
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
|
1055
1075
|
# [<tt>:on_update</tt>]
|
1056
1076
|
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
|
1077
|
+
# [<tt>:if_not_exists</tt>]
|
1078
|
+
# Specifies if the foreign key already exists to not try to re-add it. This will avoid
|
1079
|
+
# duplicate column errors.
|
1057
1080
|
# [<tt>:validate</tt>]
|
1058
1081
|
# (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
|
1082
|
+
# [<tt>:deferrable</tt>]
|
1083
|
+
# (PostgreSQL only) Specify whether or not the foreign key should be deferrable. Valid values are booleans or
|
1084
|
+
# +:deferred+ or +:immediate+ to specify the default behavior. Defaults to +false+.
|
1059
1085
|
def add_foreign_key(from_table, to_table, **options)
|
1060
1086
|
return unless supports_foreign_keys?
|
1087
|
+
return if options[:if_not_exists] == true && foreign_key_exists?(from_table, to_table)
|
1061
1088
|
|
1062
1089
|
options = foreign_key_options(from_table, to_table, options)
|
1063
1090
|
at = create_alter_table from_table
|
@@ -1087,12 +1114,18 @@ module ActiveRecord
|
|
1087
1114
|
#
|
1088
1115
|
# remove_foreign_key :accounts, name: :special_fk_name
|
1089
1116
|
#
|
1117
|
+
# Checks if the foreign key exists before trying to remove it. Will silently ignore indexes that
|
1118
|
+
# don't exist.
|
1119
|
+
#
|
1120
|
+
# remove_foreign_key :accounts, :branches, if_exists: true
|
1121
|
+
#
|
1090
1122
|
# The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key
|
1091
1123
|
# with an addition of
|
1092
1124
|
# [<tt>:to_table</tt>]
|
1093
1125
|
# The name of the table that contains the referenced primary key.
|
1094
1126
|
def remove_foreign_key(from_table, to_table = nil, **options)
|
1095
1127
|
return unless supports_foreign_keys?
|
1128
|
+
return if options[:if_exists] == true && !foreign_key_exists?(from_table, to_table)
|
1096
1129
|
|
1097
1130
|
fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
|
1098
1131
|
|
@@ -1256,6 +1289,25 @@ module ActiveRecord
|
|
1256
1289
|
columns
|
1257
1290
|
end
|
1258
1291
|
|
1292
|
+
def distinct_relation_for_primary_key(relation) # :nodoc:
|
1293
|
+
values = columns_for_distinct(
|
1294
|
+
visitor.compile(relation.table[relation.primary_key]),
|
1295
|
+
relation.order_values
|
1296
|
+
)
|
1297
|
+
|
1298
|
+
limited = relation.reselect(values).distinct!
|
1299
|
+
limited_ids = select_rows(limited.arel, "SQL").map(&:last)
|
1300
|
+
|
1301
|
+
if limited_ids.empty?
|
1302
|
+
relation.none!
|
1303
|
+
else
|
1304
|
+
relation.where!(relation.primary_key => limited_ids)
|
1305
|
+
end
|
1306
|
+
|
1307
|
+
relation.limit_value = relation.offset_value = nil
|
1308
|
+
relation
|
1309
|
+
end
|
1310
|
+
|
1259
1311
|
# Adds timestamps (+created_at+ and +updated_at+) columns to +table_name+.
|
1260
1312
|
# Additional options (like +:null+) are forwarded to #add_column.
|
1261
1313
|
#
|
@@ -1277,11 +1329,10 @@ module ActiveRecord
|
|
1277
1329
|
# remove_timestamps(:suppliers)
|
1278
1330
|
#
|
1279
1331
|
def remove_timestamps(table_name, **options)
|
1280
|
-
|
1281
|
-
remove_column table_name, :created_at
|
1332
|
+
remove_columns table_name, :updated_at, :created_at
|
1282
1333
|
end
|
1283
1334
|
|
1284
|
-
def update_table_definition(table_name, base)
|
1335
|
+
def update_table_definition(table_name, base) # :nodoc:
|
1285
1336
|
Table.new(table_name, base)
|
1286
1337
|
end
|
1287
1338
|
|
@@ -1488,7 +1539,7 @@ module ActiveRecord
|
|
1488
1539
|
def foreign_key_name(table_name, options)
|
1489
1540
|
options.fetch(:name) do
|
1490
1541
|
identifier = "#{table_name}_#{options.fetch(:column)}_fk"
|
1491
|
-
hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
|
1542
|
+
hashed_identifier = OpenSSL::Digest::SHA256.hexdigest(identifier).first(10)
|
1492
1543
|
|
1493
1544
|
"fk_rails_#{hashed_identifier}"
|
1494
1545
|
end
|
@@ -1516,7 +1567,7 @@ module ActiveRecord
|
|
1516
1567
|
options.fetch(:name) do
|
1517
1568
|
expression = options.fetch(:expression)
|
1518
1569
|
identifier = "#{table_name}_#{expression}_chk"
|
1519
|
-
hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
|
1570
|
+
hashed_identifier = OpenSSL::Digest::SHA256.hexdigest(identifier).first(10)
|
1520
1571
|
|
1521
1572
|
"chk_rails_#{hashed_identifier}"
|
1522
1573
|
end
|
@@ -73,7 +73,7 @@ module ActiveRecord
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
-
class NullTransaction
|
76
|
+
class NullTransaction # :nodoc:
|
77
77
|
def initialize; end
|
78
78
|
def state; end
|
79
79
|
def closed?; true; end
|
@@ -82,7 +82,7 @@ module ActiveRecord
|
|
82
82
|
def add_record(record, _ = true); end
|
83
83
|
end
|
84
84
|
|
85
|
-
class Transaction
|
85
|
+
class Transaction # :nodoc:
|
86
86
|
attr_reader :connection, :state, :savepoint_name, :isolation_level
|
87
87
|
attr_accessor :written
|
88
88
|
|
@@ -221,7 +221,7 @@ module ActiveRecord
|
|
221
221
|
end
|
222
222
|
end
|
223
223
|
|
224
|
-
class TransactionManager
|
224
|
+
class TransactionManager # :nodoc:
|
225
225
|
def initialize(connection)
|
226
226
|
@stack = []
|
227
227
|
@connection = connection
|
@@ -333,26 +333,19 @@ module ActiveRecord
|
|
333
333
|
# @connection still holds an open or invalid transaction, so we must not
|
334
334
|
# put it back in the pool for reuse.
|
335
335
|
@connection.throw_away! unless transaction.state.rolledback?
|
336
|
+
elsif Thread.current.status == "aborting" || (!completed && transaction.written)
|
337
|
+
# The transaction is still open but the block returned earlier.
|
338
|
+
#
|
339
|
+
# The block could return early because of a timeout or because the thread is aborting,
|
340
|
+
# so we are rolling back to make sure the timeout didn't caused the transaction to be
|
341
|
+
# committed incompletely.
|
342
|
+
rollback_transaction
|
336
343
|
else
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
Using `return`, `break` or `throw` to exit a transaction block is
|
343
|
-
deprecated without replacement. If the `throw` came from
|
344
|
-
`Timeout.timeout(duration)`, pass an exception class as a second
|
345
|
-
argument so it doesn't use `throw` to abort its block. This results
|
346
|
-
in the transaction being committed, but in the next release of Rails
|
347
|
-
it will rollback.
|
348
|
-
EOW
|
349
|
-
end
|
350
|
-
begin
|
351
|
-
commit_transaction
|
352
|
-
rescue Exception
|
353
|
-
rollback_transaction(transaction) unless transaction.state.completed?
|
354
|
-
raise
|
355
|
-
end
|
344
|
+
begin
|
345
|
+
commit_transaction
|
346
|
+
rescue Exception
|
347
|
+
rollback_transaction(transaction) unless transaction.state.completed?
|
348
|
+
raise
|
356
349
|
end
|
357
350
|
end
|
358
351
|
end
|
@@ -36,7 +36,7 @@ module ActiveRecord
|
|
36
36
|
include Savepoints
|
37
37
|
|
38
38
|
SIMPLE_INT = /\A\d+\z/
|
39
|
-
COMMENT_REGEX = %r{(
|
39
|
+
COMMENT_REGEX = %r{(?:--.*\n)*|/\*(?:[^*]|\*[^/])*\*/}m
|
40
40
|
|
41
41
|
attr_accessor :pool
|
42
42
|
attr_reader :visitor, :owner, :logger, :lock
|
@@ -68,7 +68,7 @@ module ActiveRecord
|
|
68
68
|
def self.build_read_query_regexp(*parts) # :nodoc:
|
69
69
|
parts += DEFAULT_READ_QUERY
|
70
70
|
parts = parts.map { |part| /#{part}/i }
|
71
|
-
/\A(?:[
|
71
|
+
/\A(?:[(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
|
72
72
|
end
|
73
73
|
|
74
74
|
def self.quoted_column_names # :nodoc:
|
@@ -88,7 +88,7 @@ module ActiveRecord
|
|
88
88
|
@logger = logger
|
89
89
|
@config = config
|
90
90
|
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
91
|
-
@idle_since =
|
91
|
+
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
92
92
|
@visitor = arel_visitor
|
93
93
|
@statements = build_statement_pool
|
94
94
|
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
@@ -102,6 +102,25 @@ module ActiveRecord
|
|
102
102
|
)
|
103
103
|
end
|
104
104
|
|
105
|
+
EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
|
106
|
+
EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze # :nodoc:
|
107
|
+
private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
|
108
|
+
def with_instrumenter(instrumenter, &block) # :nodoc:
|
109
|
+
Thread.handle_interrupt(EXCEPTION_NEVER) do
|
110
|
+
previous_instrumenter = @instrumenter
|
111
|
+
@instrumenter = instrumenter
|
112
|
+
Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
|
113
|
+
ensure
|
114
|
+
@instrumenter = previous_instrumenter
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def check_if_write_query(sql) # :nodoc:
|
119
|
+
if preventing_writes? && write_query?(sql)
|
120
|
+
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
105
124
|
def replica?
|
106
125
|
@config[:replica] || false
|
107
126
|
end
|
@@ -121,10 +140,10 @@ module ActiveRecord
|
|
121
140
|
# will return true based on +current_preventing_writes+.
|
122
141
|
def preventing_writes?
|
123
142
|
return true if replica?
|
124
|
-
return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord
|
125
|
-
return false if
|
143
|
+
return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord.legacy_connection_handling
|
144
|
+
return false if connection_class.nil?
|
126
145
|
|
127
|
-
|
146
|
+
connection_class.current_preventing_writes
|
128
147
|
end
|
129
148
|
|
130
149
|
def migrations_paths # :nodoc:
|
@@ -159,7 +178,7 @@ module ActiveRecord
|
|
159
178
|
alias :prepared_statements :prepared_statements?
|
160
179
|
|
161
180
|
def prepared_statements_disabled_cache # :nodoc:
|
162
|
-
|
181
|
+
ActiveSupport::IsolatedExecutionState[:active_record_prepared_statements_disabled_cache] ||= Set.new
|
163
182
|
end
|
164
183
|
|
165
184
|
class Version
|
@@ -201,8 +220,20 @@ module ActiveRecord
|
|
201
220
|
@owner = Thread.current
|
202
221
|
end
|
203
222
|
|
204
|
-
def
|
205
|
-
@pool.
|
223
|
+
def connection_class # :nodoc:
|
224
|
+
@pool.connection_class
|
225
|
+
end
|
226
|
+
|
227
|
+
# The role (ie :writing) for the current connection. In a
|
228
|
+
# non-multi role application, `:writing` is returned.
|
229
|
+
def role
|
230
|
+
@pool.role
|
231
|
+
end
|
232
|
+
|
233
|
+
# The shard (ie :default) for the current connection. In
|
234
|
+
# a non-sharded application, `:default` is returned.
|
235
|
+
def shard
|
236
|
+
@pool.shard
|
206
237
|
end
|
207
238
|
|
208
239
|
def schema_cache
|
@@ -223,7 +254,7 @@ module ActiveRecord
|
|
223
254
|
"Current thread: #{Thread.current}."
|
224
255
|
end
|
225
256
|
|
226
|
-
@idle_since =
|
257
|
+
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
227
258
|
@owner = nil
|
228
259
|
else
|
229
260
|
raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
|
@@ -246,7 +277,7 @@ module ActiveRecord
|
|
246
277
|
# Seconds since this connection was returned to the pool
|
247
278
|
def seconds_idle # :nodoc:
|
248
279
|
return 0 if in_use?
|
249
|
-
|
280
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) - @idle_since
|
250
281
|
end
|
251
282
|
|
252
283
|
def unprepared_statement
|
@@ -344,6 +375,11 @@ module ActiveRecord
|
|
344
375
|
false
|
345
376
|
end
|
346
377
|
|
378
|
+
# Does this adapter support creating deferrable constraints?
|
379
|
+
def supports_deferrable_constraints?
|
380
|
+
false
|
381
|
+
end
|
382
|
+
|
347
383
|
# Does this adapter support creating check constraints?
|
348
384
|
def supports_check_constraints?
|
349
385
|
false
|
@@ -418,6 +454,15 @@ module ActiveRecord
|
|
418
454
|
false
|
419
455
|
end
|
420
456
|
|
457
|
+
def supports_concurrent_connections?
|
458
|
+
true
|
459
|
+
end
|
460
|
+
|
461
|
+
def async_enabled? # :nodoc:
|
462
|
+
supports_concurrent_connections? &&
|
463
|
+
!ActiveRecord.async_query_executor.nil? && !pool.async_executor.nil?
|
464
|
+
end
|
465
|
+
|
421
466
|
# This is meant to be implemented by the adapters that support extensions
|
422
467
|
def disable_extension(name)
|
423
468
|
end
|
@@ -426,6 +471,10 @@ module ActiveRecord
|
|
426
471
|
def enable_extension(name)
|
427
472
|
end
|
428
473
|
|
474
|
+
# This is meant to be implemented by the adapters that support custom enum types
|
475
|
+
def create_enum(*) # :nodoc:
|
476
|
+
end
|
477
|
+
|
429
478
|
def advisory_locks_enabled? # :nodoc:
|
430
479
|
supports_advisory_locks? && @advisory_locks_enabled
|
431
480
|
end
|
@@ -461,6 +510,11 @@ module ActiveRecord
|
|
461
510
|
yield
|
462
511
|
end
|
463
512
|
|
513
|
+
# Override to check all foreign key constraints in a database.
|
514
|
+
def all_foreign_keys_valid?
|
515
|
+
true
|
516
|
+
end
|
517
|
+
|
464
518
|
# CONNECTION MANAGEMENT ====================================
|
465
519
|
|
466
520
|
# Checks whether the connection to the database is still active. This includes
|
@@ -599,78 +653,93 @@ module ActiveRecord
|
|
599
653
|
def check_version # :nodoc:
|
600
654
|
end
|
601
655
|
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
656
|
+
# Returns the version identifier of the schema currently available in
|
657
|
+
# the database. This is generally equal to the number of the highest-
|
658
|
+
# numbered migration that has been executed, or 0 if no schema
|
659
|
+
# information is present / the database is empty.
|
660
|
+
def schema_version
|
661
|
+
migration_context.current_version
|
662
|
+
end
|
663
|
+
|
664
|
+
def field_ordered_value(column, values) # :nodoc:
|
665
|
+
node = Arel::Nodes::Case.new(column)
|
666
|
+
values.each.with_index(1) do |value, order|
|
667
|
+
node.when(value).then(order)
|
607
668
|
end
|
608
669
|
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
670
|
+
Arel::Nodes::Ascending.new(node.else(values.length + 1))
|
671
|
+
end
|
672
|
+
|
673
|
+
class << self
|
674
|
+
private
|
675
|
+
def initialize_type_map(m)
|
676
|
+
register_class_with_limit m, %r(boolean)i, Type::Boolean
|
677
|
+
register_class_with_limit m, %r(char)i, Type::String
|
678
|
+
register_class_with_limit m, %r(binary)i, Type::Binary
|
679
|
+
register_class_with_limit m, %r(text)i, Type::Text
|
680
|
+
register_class_with_precision m, %r(date)i, Type::Date
|
681
|
+
register_class_with_precision m, %r(time)i, Type::Time
|
682
|
+
register_class_with_precision m, %r(datetime)i, Type::DateTime
|
683
|
+
register_class_with_limit m, %r(float)i, Type::Float
|
684
|
+
register_class_with_limit m, %r(int)i, Type::Integer
|
685
|
+
|
686
|
+
m.alias_type %r(blob)i, "binary"
|
687
|
+
m.alias_type %r(clob)i, "text"
|
688
|
+
m.alias_type %r(timestamp)i, "datetime"
|
689
|
+
m.alias_type %r(numeric)i, "decimal"
|
690
|
+
m.alias_type %r(number)i, "decimal"
|
691
|
+
m.alias_type %r(double)i, "float"
|
692
|
+
|
693
|
+
m.register_type %r(^json)i, Type::Json.new
|
694
|
+
|
695
|
+
m.register_type(%r(decimal)i) do |sql_type|
|
696
|
+
scale = extract_scale(sql_type)
|
697
|
+
precision = extract_precision(sql_type)
|
698
|
+
|
699
|
+
if scale == 0
|
700
|
+
# FIXME: Remove this class as well
|
701
|
+
Type::DecimalWithoutScale.new(precision: precision)
|
702
|
+
else
|
703
|
+
Type::Decimal.new(precision: precision, scale: scale)
|
704
|
+
end
|
638
705
|
end
|
639
706
|
end
|
640
|
-
end
|
641
707
|
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
708
|
+
def register_class_with_limit(mapping, key, klass)
|
709
|
+
mapping.register_type(key) do |*args|
|
710
|
+
limit = extract_limit(args.last)
|
711
|
+
klass.new(limit: limit)
|
712
|
+
end
|
713
|
+
end
|
646
714
|
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
715
|
+
def register_class_with_precision(mapping, key, klass)
|
716
|
+
mapping.register_type(key) do |*args|
|
717
|
+
precision = extract_precision(args.last)
|
718
|
+
klass.new(precision: precision)
|
719
|
+
end
|
651
720
|
end
|
652
|
-
end
|
653
721
|
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
722
|
+
def extract_scale(sql_type)
|
723
|
+
case sql_type
|
724
|
+
when /\((\d+)\)/ then 0
|
725
|
+
when /\((\d+)(,(\d+))\)/ then $3.to_i
|
726
|
+
end
|
658
727
|
end
|
659
|
-
end
|
660
728
|
|
661
|
-
|
662
|
-
|
663
|
-
when /\((\d+)\)/ then 0
|
664
|
-
when /\((\d+)(,(\d+))\)/ then $3.to_i
|
729
|
+
def extract_precision(sql_type)
|
730
|
+
$1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
|
665
731
|
end
|
666
|
-
end
|
667
732
|
|
668
|
-
|
669
|
-
|
670
|
-
|
733
|
+
def extract_limit(sql_type)
|
734
|
+
$1.to_i if sql_type =~ /\((.*)\)/
|
735
|
+
end
|
736
|
+
end
|
737
|
+
|
738
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
671
739
|
|
672
|
-
|
673
|
-
|
740
|
+
private
|
741
|
+
def type_map
|
742
|
+
TYPE_MAP
|
674
743
|
end
|
675
744
|
|
676
745
|
def translate_exception_class(e, sql, binds)
|
@@ -683,7 +752,7 @@ module ActiveRecord
|
|
683
752
|
exception
|
684
753
|
end
|
685
754
|
|
686
|
-
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil) # :doc:
|
755
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false, &block) # :doc:
|
687
756
|
@instrumenter.instrument(
|
688
757
|
"sql.active_record",
|
689
758
|
sql: sql,
|
@@ -691,15 +760,21 @@ module ActiveRecord
|
|
691
760
|
binds: binds,
|
692
761
|
type_casted_binds: type_casted_binds,
|
693
762
|
statement_name: statement_name,
|
763
|
+
async: async,
|
694
764
|
connection: self) do
|
695
|
-
@lock.synchronize
|
696
|
-
yield
|
697
|
-
end
|
765
|
+
@lock.synchronize(&block)
|
698
766
|
rescue => e
|
699
767
|
raise translate_exception_class(e, sql, binds)
|
700
768
|
end
|
701
769
|
end
|
702
770
|
|
771
|
+
def transform_query(sql)
|
772
|
+
ActiveRecord.query_transformers.each do |transformer|
|
773
|
+
sql = transformer.call(sql)
|
774
|
+
end
|
775
|
+
sql
|
776
|
+
end
|
777
|
+
|
703
778
|
def translate_exception(exception, message:, sql:, binds:)
|
704
779
|
# override in derived class
|
705
780
|
case exception
|