activerecord 6.1.4.1 → 7.0.0.rc2
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 +1050 -981
- 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 +55 -12
@@ -18,10 +18,9 @@ module ActiveRecord
|
|
18
18
|
SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
|
19
19
|
end
|
20
20
|
|
21
|
-
def execute(sql, name = nil)
|
22
|
-
|
23
|
-
|
24
|
-
end
|
21
|
+
def execute(sql, name = nil) # :nodoc:
|
22
|
+
sql = transform_query(sql)
|
23
|
+
check_if_write_query(sql)
|
25
24
|
|
26
25
|
materialize_transactions
|
27
26
|
mark_transaction_written_if_write(sql)
|
@@ -33,17 +32,16 @@ module ActiveRecord
|
|
33
32
|
end
|
34
33
|
end
|
35
34
|
|
36
|
-
def exec_query(sql, name = nil, binds = [], prepare: false)
|
37
|
-
|
38
|
-
|
39
|
-
end
|
35
|
+
def exec_query(sql, name = nil, binds = [], prepare: false, async: false) # :nodoc:
|
36
|
+
sql = transform_query(sql)
|
37
|
+
check_if_write_query(sql)
|
40
38
|
|
41
39
|
materialize_transactions
|
42
40
|
mark_transaction_written_if_write(sql)
|
43
41
|
|
44
42
|
type_casted_binds = type_casted_binds(binds)
|
45
43
|
|
46
|
-
log(sql, name, binds, type_casted_binds) do
|
44
|
+
log(sql, name, binds, type_casted_binds, async: async) do
|
47
45
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
48
46
|
# Don't cache statements if they are not prepared
|
49
47
|
unless prepare
|
@@ -70,49 +68,57 @@ module ActiveRecord
|
|
70
68
|
end
|
71
69
|
end
|
72
70
|
|
73
|
-
def exec_delete(sql, name = "SQL", binds = [])
|
71
|
+
def exec_delete(sql, name = "SQL", binds = []) # :nodoc:
|
74
72
|
exec_query(sql, name, binds)
|
75
73
|
@connection.changes
|
76
74
|
end
|
77
75
|
alias :exec_update :exec_delete
|
78
76
|
|
79
|
-
def begin_isolated_db_transaction(isolation)
|
77
|
+
def begin_isolated_db_transaction(isolation) # :nodoc:
|
80
78
|
raise TransactionIsolationError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted
|
81
79
|
raise StandardError, "You need to enable the shared-cache mode in SQLite mode before attempting to change the transaction isolation level" unless shared_cache?
|
82
80
|
|
83
|
-
|
81
|
+
ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted] = @connection.get_first_value("PRAGMA read_uncommitted")
|
84
82
|
@connection.read_uncommitted = true
|
85
83
|
begin_db_transaction
|
86
84
|
end
|
87
85
|
|
88
|
-
def begin_db_transaction
|
86
|
+
def begin_db_transaction # :nodoc:
|
89
87
|
log("begin transaction", "TRANSACTION") { @connection.transaction }
|
90
88
|
end
|
91
89
|
|
92
|
-
def commit_db_transaction
|
90
|
+
def commit_db_transaction # :nodoc:
|
93
91
|
log("commit transaction", "TRANSACTION") { @connection.commit }
|
94
92
|
reset_read_uncommitted
|
95
93
|
end
|
96
94
|
|
97
|
-
def exec_rollback_db_transaction
|
95
|
+
def exec_rollback_db_transaction # :nodoc:
|
98
96
|
log("rollback transaction", "TRANSACTION") { @connection.rollback }
|
99
97
|
reset_read_uncommitted
|
100
98
|
end
|
101
99
|
|
100
|
+
# https://stackoverflow.com/questions/17574784
|
101
|
+
# https://www.sqlite.org/lang_datefunc.html
|
102
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')").freeze # :nodoc:
|
103
|
+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
104
|
+
|
105
|
+
def high_precision_current_timestamp
|
106
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP
|
107
|
+
end
|
108
|
+
|
102
109
|
private
|
103
110
|
def reset_read_uncommitted
|
104
|
-
read_uncommitted =
|
111
|
+
read_uncommitted = ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted]
|
105
112
|
return unless read_uncommitted
|
106
113
|
|
107
114
|
@connection.read_uncommitted = read_uncommitted
|
108
115
|
end
|
109
116
|
|
110
117
|
def execute_batch(statements, name = nil)
|
118
|
+
statements = statements.map { |sql| transform_query(sql) }
|
111
119
|
sql = combine_multi_statements(statements)
|
112
120
|
|
113
|
-
|
114
|
-
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
115
|
-
end
|
121
|
+
check_if_write_query(sql)
|
116
122
|
|
117
123
|
materialize_transactions
|
118
124
|
mark_transaction_written_if_write(sql)
|
@@ -45,6 +45,21 @@ module ActiveRecord
|
|
45
45
|
0
|
46
46
|
end
|
47
47
|
|
48
|
+
def type_cast(value) # :nodoc:
|
49
|
+
case value
|
50
|
+
when BigDecimal
|
51
|
+
value.to_f
|
52
|
+
when String
|
53
|
+
if value.encoding == Encoding::ASCII_8BIT
|
54
|
+
super(value.encode(Encoding::UTF_8))
|
55
|
+
else
|
56
|
+
super
|
57
|
+
end
|
58
|
+
else
|
59
|
+
super
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
48
63
|
def column_name_matcher
|
49
64
|
COLUMN_NAME
|
50
65
|
end
|
@@ -80,22 +95,6 @@ module ActiveRecord
|
|
80
95
|
/ix
|
81
96
|
|
82
97
|
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
83
|
-
|
84
|
-
private
|
85
|
-
def _type_cast(value)
|
86
|
-
case value
|
87
|
-
when BigDecimal
|
88
|
-
value.to_f
|
89
|
-
when String
|
90
|
-
if value.encoding == Encoding::ASCII_8BIT
|
91
|
-
super(value.encode(Encoding::UTF_8))
|
92
|
-
else
|
93
|
-
super
|
94
|
-
end
|
95
|
-
else
|
96
|
-
super
|
97
|
-
end
|
98
|
-
end
|
99
98
|
end
|
100
99
|
end
|
101
100
|
end
|
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
6
6
|
module SchemaStatements # :nodoc:
|
7
7
|
# Returns an array of indexes for the given table.
|
8
8
|
def indexes(table_name)
|
9
|
-
exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").
|
9
|
+
exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").filter_map do |row|
|
10
10
|
# Indexes SQLite creates implicitly for internal use start with "sqlite_".
|
11
11
|
# See https://www.sqlite.org/fileformat2.html#intschema
|
12
12
|
next if row["name"].start_with?("sqlite_")
|
@@ -49,7 +49,7 @@ module ActiveRecord
|
|
49
49
|
where: where,
|
50
50
|
orders: orders
|
51
51
|
)
|
52
|
-
end
|
52
|
+
end
|
53
53
|
end
|
54
54
|
|
55
55
|
def add_foreign_key(from_table, to_table, **options)
|
@@ -60,6 +60,8 @@ module ActiveRecord
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def remove_foreign_key(from_table, to_table = nil, **options)
|
63
|
+
return if options[:if_exists] == true && !foreign_key_exists?(from_table, to_table)
|
64
|
+
|
63
65
|
to_table ||= options[:to_table]
|
64
66
|
options = options.except(:name, :to_table, :validate)
|
65
67
|
foreign_keys = foreign_keys(from_table)
|
@@ -47,7 +47,7 @@ module ActiveRecord
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
module ConnectionAdapters
|
50
|
+
module ConnectionAdapters # :nodoc:
|
51
51
|
# The SQLite3 adapter works with the sqlite3-ruby drivers
|
52
52
|
# (available as gem from https://rubygems.org/gems/sqlite3).
|
53
53
|
#
|
@@ -84,6 +84,7 @@ module ActiveRecord
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def initialize(connection, logger, connection_options, config)
|
87
|
+
@memory_database = config[:database] == ":memory:"
|
87
88
|
super(connection, logger, config)
|
88
89
|
configure_connection
|
89
90
|
end
|
@@ -153,6 +154,10 @@ module ActiveRecord
|
|
153
154
|
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
154
155
|
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
155
156
|
|
157
|
+
def supports_concurrent_connections?
|
158
|
+
!@memory_database
|
159
|
+
end
|
160
|
+
|
156
161
|
def active?
|
157
162
|
!@connection.closed?
|
158
163
|
end
|
@@ -173,11 +178,11 @@ module ActiveRecord
|
|
173
178
|
true
|
174
179
|
end
|
175
180
|
|
176
|
-
def native_database_types
|
181
|
+
def native_database_types # :nodoc:
|
177
182
|
NATIVE_DATABASE_TYPES
|
178
183
|
end
|
179
184
|
|
180
|
-
# Returns the current database encoding format as a string,
|
185
|
+
# Returns the current database encoding format as a string, e.g. 'UTF-8'
|
181
186
|
def encoding
|
182
187
|
@connection.encoding.to_s
|
183
188
|
end
|
@@ -206,6 +211,10 @@ module ActiveRecord
|
|
206
211
|
end
|
207
212
|
end
|
208
213
|
|
214
|
+
def all_foreign_keys_valid? # :nodoc:
|
215
|
+
execute("PRAGMA foreign_key_check").blank?
|
216
|
+
end
|
217
|
+
|
209
218
|
# SCHEMA STATEMENTS ========================================
|
210
219
|
|
211
220
|
def primary_keys(table_name) # :nodoc:
|
@@ -232,7 +241,7 @@ module ActiveRecord
|
|
232
241
|
rename_table_indexes(table_name, new_name)
|
233
242
|
end
|
234
243
|
|
235
|
-
def add_column(table_name, column_name, type, **options)
|
244
|
+
def add_column(table_name, column_name, type, **options) # :nodoc:
|
236
245
|
if invalid_alter_table_type?(type, options)
|
237
246
|
alter_table(table_name) do |definition|
|
238
247
|
definition.column(column_name, type, **options)
|
@@ -242,16 +251,24 @@ module ActiveRecord
|
|
242
251
|
end
|
243
252
|
end
|
244
253
|
|
245
|
-
def remove_column(table_name, column_name, type = nil, **options)
|
254
|
+
def remove_column(table_name, column_name, type = nil, **options) # :nodoc:
|
246
255
|
alter_table(table_name) do |definition|
|
247
256
|
definition.remove_column column_name
|
248
|
-
definition.foreign_keys.delete_if
|
249
|
-
|
257
|
+
definition.foreign_keys.delete_if { |fk| fk.column == column_name.to_s }
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def remove_columns(table_name, *column_names, type: nil, **options) # :nodoc:
|
262
|
+
alter_table(table_name) do |definition|
|
263
|
+
column_names.each do |column_name|
|
264
|
+
definition.remove_column column_name
|
250
265
|
end
|
266
|
+
column_names = column_names.map(&:to_s)
|
267
|
+
definition.foreign_keys.delete_if { |fk| column_names.include?(fk.column) }
|
251
268
|
end
|
252
269
|
end
|
253
270
|
|
254
|
-
def change_column_default(table_name, column_name, default_or_changes)
|
271
|
+
def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
|
255
272
|
default = extract_new_default_value(default_or_changes)
|
256
273
|
|
257
274
|
alter_table(table_name) do |definition|
|
@@ -259,7 +276,7 @@ module ActiveRecord
|
|
259
276
|
end
|
260
277
|
end
|
261
278
|
|
262
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
279
|
+
def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
|
263
280
|
unless null || default.nil?
|
264
281
|
exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
265
282
|
end
|
@@ -268,7 +285,7 @@ module ActiveRecord
|
|
268
285
|
end
|
269
286
|
end
|
270
287
|
|
271
|
-
def change_column(table_name, column_name, type, **options)
|
288
|
+
def change_column(table_name, column_name, type, **options) # :nodoc:
|
272
289
|
alter_table(table_name) do |definition|
|
273
290
|
definition[column_name].instance_eval do
|
274
291
|
self.type = aliased_types(type.to_s, type)
|
@@ -277,7 +294,7 @@ module ActiveRecord
|
|
277
294
|
end
|
278
295
|
end
|
279
296
|
|
280
|
-
def rename_column(table_name, column_name, new_column_name)
|
297
|
+
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
281
298
|
column = column_for(table_name, column_name)
|
282
299
|
alter_table(table_name, rename: { column.name => new_column_name.to_s })
|
283
300
|
rename_column_indexes(table_name, column.name, new_column_name)
|
@@ -308,8 +325,12 @@ module ActiveRecord
|
|
308
325
|
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
309
326
|
elsif insert.update_duplicates?
|
310
327
|
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
311
|
-
|
312
|
-
|
328
|
+
if insert.raw_update_sql?
|
329
|
+
sql << insert.raw_update_sql
|
330
|
+
else
|
331
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
|
332
|
+
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
333
|
+
end
|
313
334
|
end
|
314
335
|
|
315
336
|
sql
|
@@ -329,18 +350,38 @@ module ActiveRecord
|
|
329
350
|
end
|
330
351
|
end
|
331
352
|
|
353
|
+
class SQLite3Integer < Type::Integer # :nodoc:
|
354
|
+
private
|
355
|
+
def _limit
|
356
|
+
# INTEGER storage class can be stored 8 bytes value.
|
357
|
+
# See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
|
358
|
+
limit || 8
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
|
363
|
+
|
364
|
+
class << self
|
365
|
+
private
|
366
|
+
def initialize_type_map(m)
|
367
|
+
super
|
368
|
+
register_class_with_limit m, %r(int)i, SQLite3Integer
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
373
|
+
|
332
374
|
private
|
375
|
+
def type_map
|
376
|
+
TYPE_MAP
|
377
|
+
end
|
378
|
+
|
333
379
|
# See https://www.sqlite.org/limits.html,
|
334
380
|
# the default value is 999 when not configured.
|
335
381
|
def bind_params_length
|
336
382
|
999
|
337
383
|
end
|
338
384
|
|
339
|
-
def initialize_type_map(m = type_map)
|
340
|
-
super
|
341
|
-
register_class_with_limit m, %r(int)i, SQLite3Integer
|
342
|
-
end
|
343
|
-
|
344
385
|
def table_structure(table_name)
|
345
386
|
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
|
346
387
|
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
|
@@ -446,6 +487,7 @@ module ActiveRecord
|
|
446
487
|
options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
|
447
488
|
options[:unique] = true if index.unique
|
448
489
|
options[:where] = index.where if index.where
|
490
|
+
options[:order] = index.orders if index.orders
|
449
491
|
add_index(to, columns, **options)
|
450
492
|
end
|
451
493
|
end
|
@@ -482,7 +524,7 @@ module ActiveRecord
|
|
482
524
|
end
|
483
525
|
end
|
484
526
|
|
485
|
-
COLLATE_REGEX =
|
527
|
+
COLLATE_REGEX = /.*"(\w+)".*collate\s+"(\w+)".*/i.freeze
|
486
528
|
|
487
529
|
def table_structure_with_collation(table_name, basic_structure)
|
488
530
|
collation_hash = {}
|
@@ -544,17 +586,6 @@ module ActiveRecord
|
|
544
586
|
|
545
587
|
execute("PRAGMA foreign_keys = ON", "SCHEMA")
|
546
588
|
end
|
547
|
-
|
548
|
-
class SQLite3Integer < Type::Integer # :nodoc:
|
549
|
-
private
|
550
|
-
def _limit
|
551
|
-
# INTEGER storage class can be stored 8 bytes value.
|
552
|
-
# See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
|
553
|
-
limit || 8
|
554
|
-
end
|
555
|
-
end
|
556
|
-
|
557
|
-
ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
|
558
589
|
end
|
559
590
|
ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
|
560
591
|
end
|
@@ -27,20 +27,21 @@ module ActiveRecord
|
|
27
27
|
autoload :ReferenceDefinition
|
28
28
|
end
|
29
29
|
|
30
|
-
autoload_at "active_record/connection_adapters/abstract/connection_pool" do
|
31
|
-
autoload :ConnectionHandler
|
32
|
-
end
|
33
|
-
|
34
30
|
autoload_under "abstract" do
|
35
31
|
autoload :SchemaStatements
|
36
32
|
autoload :DatabaseStatements
|
37
33
|
autoload :DatabaseLimits
|
38
34
|
autoload :Quoting
|
39
|
-
autoload :
|
35
|
+
autoload :ConnectionHandler
|
40
36
|
autoload :QueryCache
|
41
37
|
autoload :Savepoints
|
42
38
|
end
|
43
39
|
|
40
|
+
autoload_at "active_record/connection_adapters/abstract/connection_pool" do
|
41
|
+
autoload :ConnectionPool
|
42
|
+
autoload :NullPool
|
43
|
+
end
|
44
|
+
|
44
45
|
autoload_at "active_record/connection_adapters/abstract/transaction" do
|
45
46
|
autoload :TransactionManager
|
46
47
|
autoload :NullTransaction
|
@@ -134,10 +134,8 @@ module ActiveRecord
|
|
134
134
|
# ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one_replica) do
|
135
135
|
# Dog.first # finds first Dog record stored on the shard one replica
|
136
136
|
# end
|
137
|
-
|
138
|
-
|
139
|
-
def connected_to(database: nil, role: nil, shard: nil, prevent_writes: false, &blk)
|
140
|
-
if legacy_connection_handling
|
137
|
+
def connected_to(role: nil, shard: nil, prevent_writes: false, &blk)
|
138
|
+
if ActiveRecord.legacy_connection_handling
|
141
139
|
if self != Base
|
142
140
|
raise NotImplementedError, "`connected_to` can only be called on ActiveRecord::Base with legacy connection handling."
|
143
141
|
end
|
@@ -151,31 +149,11 @@ module ActiveRecord
|
|
151
149
|
end
|
152
150
|
end
|
153
151
|
|
154
|
-
|
155
|
-
raise ArgumentError, "`connected_to` cannot accept a `database` argument with any other arguments."
|
156
|
-
elsif database
|
157
|
-
ActiveSupport::Deprecation.warn("The database key in `connected_to` is deprecated. It will be removed in Rails 6.2.0 without replacement.")
|
158
|
-
|
159
|
-
if database.is_a?(Hash)
|
160
|
-
role, database = database.first
|
161
|
-
role = role.to_sym
|
162
|
-
end
|
163
|
-
|
164
|
-
db_config, owner_name = resolve_config_for_connection(database)
|
165
|
-
handler = lookup_connection_handler(role)
|
166
|
-
|
167
|
-
handler.establish_connection(db_config, owner_name: owner_name, role: role)
|
168
|
-
|
169
|
-
with_handler(role, &blk)
|
170
|
-
elsif role || shard
|
171
|
-
unless role
|
172
|
-
raise ArgumentError, "`connected_to` cannot accept a `shard` argument without a `role`."
|
173
|
-
end
|
174
|
-
|
175
|
-
with_role_and_shard(role, shard, prevent_writes, &blk)
|
176
|
-
else
|
152
|
+
unless role || shard
|
177
153
|
raise ArgumentError, "must provide a `shard` and/or `role`."
|
178
154
|
end
|
155
|
+
|
156
|
+
with_role_and_shard(role, shard, prevent_writes, &blk)
|
179
157
|
end
|
180
158
|
|
181
159
|
# Connects a role and/or shard to the provided connection names. Optionally +prevent_writes+
|
@@ -194,7 +172,7 @@ module ActiveRecord
|
|
194
172
|
def connected_to_many(*classes, role:, shard: nil, prevent_writes: false)
|
195
173
|
classes = classes.flatten
|
196
174
|
|
197
|
-
if legacy_connection_handling
|
175
|
+
if ActiveRecord.legacy_connection_handling
|
198
176
|
raise NotImplementedError, "connected_to_many is not available with legacy connection handling"
|
199
177
|
end
|
200
178
|
|
@@ -202,9 +180,9 @@ module ActiveRecord
|
|
202
180
|
raise NotImplementedError, "connected_to_many can only be called on ActiveRecord::Base."
|
203
181
|
end
|
204
182
|
|
205
|
-
prevent_writes = true if role == reading_role
|
183
|
+
prevent_writes = true if role == ActiveRecord.reading_role
|
206
184
|
|
207
|
-
|
185
|
+
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes)
|
208
186
|
yield
|
209
187
|
ensure
|
210
188
|
connected_to_stack.pop
|
@@ -218,13 +196,32 @@ module ActiveRecord
|
|
218
196
|
# It is not recommended to use this method in a request since it
|
219
197
|
# does not yield to a block like +connected_to+.
|
220
198
|
def connecting_to(role: default_role, shard: default_shard, prevent_writes: false)
|
221
|
-
if legacy_connection_handling
|
199
|
+
if ActiveRecord.legacy_connection_handling
|
222
200
|
raise NotImplementedError, "`connecting_to` is not available with `legacy_connection_handling`."
|
223
201
|
end
|
224
202
|
|
225
|
-
prevent_writes = true if role == reading_role
|
203
|
+
prevent_writes = true if role == ActiveRecord.reading_role
|
226
204
|
|
227
|
-
|
205
|
+
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
|
206
|
+
end
|
207
|
+
|
208
|
+
# Prohibit swapping shards while inside of the passed block.
|
209
|
+
#
|
210
|
+
# In some cases you may want to be able to swap shards but not allow a
|
211
|
+
# nested call to connected_to or connected_to_many to swap again. This
|
212
|
+
# is useful in cases you're using sharding to provide per-request
|
213
|
+
# database isolation.
|
214
|
+
def prohibit_shard_swapping(enabled = true)
|
215
|
+
prev_value = ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping]
|
216
|
+
ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping] = enabled
|
217
|
+
yield
|
218
|
+
ensure
|
219
|
+
ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping] = prev_value
|
220
|
+
end
|
221
|
+
|
222
|
+
# Determine whether or not shard swapping is currently prohibited
|
223
|
+
def shard_swapping_prohibited?
|
224
|
+
ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping]
|
228
225
|
end
|
229
226
|
|
230
227
|
# Prevent writing to the database regardless of role.
|
@@ -239,7 +236,7 @@ module ActiveRecord
|
|
239
236
|
# See +READ_QUERY+ for the queries that are blocked by this
|
240
237
|
# method.
|
241
238
|
def while_preventing_writes(enabled = true, &block)
|
242
|
-
if legacy_connection_handling
|
239
|
+
if ActiveRecord.legacy_connection_handling
|
243
240
|
connection_handler.while_preventing_writes(enabled, &block)
|
244
241
|
else
|
245
242
|
connected_to(role: current_role, prevent_writes: enabled, &block)
|
@@ -257,8 +254,8 @@ module ActiveRecord
|
|
257
254
|
end
|
258
255
|
|
259
256
|
def lookup_connection_handler(handler_key) # :nodoc:
|
260
|
-
if ActiveRecord
|
261
|
-
handler_key ||= ActiveRecord
|
257
|
+
if ActiveRecord.legacy_connection_handling
|
258
|
+
handler_key ||= ActiveRecord.writing_role
|
262
259
|
connection_handlers[handler_key] ||= ActiveRecord::ConnectionAdapters::ConnectionHandler.new
|
263
260
|
else
|
264
261
|
ActiveRecord::Base.connection_handler
|
@@ -267,7 +264,7 @@ module ActiveRecord
|
|
267
264
|
|
268
265
|
# Clears the query cache for all connections associated with the current thread.
|
269
266
|
def clear_query_caches_for_current_thread
|
270
|
-
if ActiveRecord
|
267
|
+
if ActiveRecord.legacy_connection_handling
|
271
268
|
ActiveRecord::Base.connection_handlers.each_value do |handler|
|
272
269
|
clear_on_handler(handler)
|
273
270
|
end
|
@@ -294,19 +291,8 @@ module ActiveRecord
|
|
294
291
|
end
|
295
292
|
|
296
293
|
def primary_class? # :nodoc:
|
297
|
-
self == Base ||
|
298
|
-
end
|
299
|
-
|
300
|
-
# Returns the configuration of the associated connection as a hash:
|
301
|
-
#
|
302
|
-
# ActiveRecord::Base.connection_config
|
303
|
-
# # => {pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}
|
304
|
-
#
|
305
|
-
# Please use only for reading.
|
306
|
-
def connection_config
|
307
|
-
connection_pool.db_config.configuration_hash
|
294
|
+
self == Base || application_record_class?
|
308
295
|
end
|
309
|
-
deprecate connection_config: "Use connection_db_config instead"
|
310
296
|
|
311
297
|
# Returns the db_config object from the associated connection:
|
312
298
|
#
|
@@ -374,17 +360,17 @@ module ActiveRecord
|
|
374
360
|
end
|
375
361
|
|
376
362
|
def with_role_and_shard(role, shard, prevent_writes)
|
377
|
-
prevent_writes = true if role == reading_role
|
363
|
+
prevent_writes = true if role == ActiveRecord.reading_role
|
378
364
|
|
379
|
-
if ActiveRecord
|
365
|
+
if ActiveRecord.legacy_connection_handling
|
380
366
|
with_handler(role.to_sym) do
|
381
367
|
connection_handler.while_preventing_writes(prevent_writes) do
|
382
|
-
|
368
|
+
append_to_connected_to_stack(shard: shard, klasses: [self])
|
383
369
|
yield
|
384
370
|
end
|
385
371
|
end
|
386
372
|
else
|
387
|
-
|
373
|
+
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
|
388
374
|
return_value = yield
|
389
375
|
return_value.load if return_value.is_a? ActiveRecord::Relation
|
390
376
|
return_value
|
@@ -393,6 +379,14 @@ module ActiveRecord
|
|
393
379
|
self.connected_to_stack.pop
|
394
380
|
end
|
395
381
|
|
382
|
+
def append_to_connected_to_stack(entry)
|
383
|
+
if shard_swapping_prohibited? && entry[:shard].present?
|
384
|
+
raise ArgumentError, "cannot swap `shard` while shard swapping is prohibited."
|
385
|
+
end
|
386
|
+
|
387
|
+
connected_to_stack << entry
|
388
|
+
end
|
389
|
+
|
396
390
|
def swap_connection_handler(handler, &blk) # :nodoc:
|
397
391
|
old_handler, ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handler, handler
|
398
392
|
return_value = yield
|