activerecord 7.1.4.1 → 7.2.2.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 +643 -2274
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +15 -8
- data/lib/active_record/associations/belongs_to_association.rb +14 -7
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/collection_association.rb +7 -1
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +7 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +4 -4
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +2 -1
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +59 -292
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +23 -55
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +4 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods.rb +54 -63
- data/lib/active_record/attributes.rb +61 -47
- data/lib/active_record/autosave_association.rb +12 -29
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +270 -65
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +34 -17
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +189 -74
- data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -62
- data/lib/active_record/connection_adapters/abstract_adapter.rb +24 -44
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +40 -10
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +6 -0
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +16 -15
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +5 -23
- data/lib/active_record/connection_adapters/pool_config.rb +7 -6
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +17 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +29 -24
- data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +44 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +25 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +125 -75
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +15 -15
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -48
- data/lib/active_record/connection_adapters.rb +121 -0
- data/lib/active_record/connection_handling.rb +56 -41
- data/lib/active_record/core.rb +86 -38
- data/lib/active_record/counter_cache.rb +18 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
- data/lib/active_record/database_configurations/database_config.rb +19 -4
- data/lib/active_record/database_configurations/hash_config.rb +38 -34
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +24 -0
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/encryptable_record.rb +3 -3
- data/lib/active_record/encryption/encrypted_attribute_type.rb +24 -4
- data/lib/active_record/encryption/encryptor.rb +18 -3
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption.rb +2 -0
- data/lib/active_record/enum.rb +19 -2
- data/lib/active_record/errors.rb +46 -20
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -31
- data/lib/active_record/future_result.rb +8 -4
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +18 -15
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +7 -6
- data/lib/active_record/log_subscriber.rb +0 -21
- data/lib/active_record/marshalling.rb +4 -1
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +2 -3
- data/lib/active_record/migration/compatibility.rb +5 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +85 -76
- data/lib/active_record/model_schema.rb +32 -68
- data/lib/active_record/nested_attributes.rb +24 -5
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +30 -352
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +15 -0
- data/lib/active_record/querying.rb +21 -9
- data/lib/active_record/railtie.rb +42 -57
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +40 -43
- data/lib/active_record/reflection.rb +98 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
- data/lib/active_record/relation/batches.rb +14 -8
- data/lib/active_record/relation/calculations.rb +96 -63
- data/lib/active_record/relation/delegation.rb +8 -11
- data/lib/active_record/relation/finder_methods.rb +16 -2
- data/lib/active_record/relation/merger.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -3
- data/lib/active_record/relation/predicate_builder.rb +3 -3
- data/lib/active_record/relation/query_methods.rb +224 -58
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +2 -18
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +496 -72
- data/lib/active_record/result.rb +31 -44
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +24 -19
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +19 -9
- data/lib/active_record/schema_migration.rb +30 -14
- data/lib/active_record/scoping/named.rb +1 -0
- data/lib/active_record/signed_id.rb +20 -1
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/table_metadata.rb +1 -10
- data/lib/active_record/tasks/database_tasks.rb +81 -42
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
- data/lib/active_record/test_fixtures.rb +86 -89
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +2 -2
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +70 -14
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +15 -10
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +148 -39
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/nodes/binary.rb +0 -6
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +4 -3
- data/lib/arel/nodes/sql_literal.rb +7 -0
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +29 -16
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +18 -12
@@ -20,17 +20,6 @@ require "active_record/connection_adapters/postgresql/type_metadata"
|
|
20
20
|
require "active_record/connection_adapters/postgresql/utils"
|
21
21
|
|
22
22
|
module ActiveRecord
|
23
|
-
module ConnectionHandling # :nodoc:
|
24
|
-
def postgresql_adapter_class
|
25
|
-
ConnectionAdapters::PostgreSQLAdapter
|
26
|
-
end
|
27
|
-
|
28
|
-
# Establishes a connection to the database that's used by all Active Record objects
|
29
|
-
def postgresql_connection(config)
|
30
|
-
postgresql_adapter_class.new(config)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
23
|
module ConnectionAdapters
|
35
24
|
# = Active Record PostgreSQL Adapter
|
36
25
|
#
|
@@ -133,6 +122,15 @@ module ActiveRecord
|
|
133
122
|
# setting, you should immediately run <tt>bin/rails db:migrate</tt> to update the types in your schema.rb.
|
134
123
|
class_attribute :datetime_type, default: :timestamp
|
135
124
|
|
125
|
+
##
|
126
|
+
# :singleton-method:
|
127
|
+
# Toggles automatic decoding of date columns.
|
128
|
+
#
|
129
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.select_value("select '2024-01-01'::date").class #=> String
|
130
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.decode_dates = true
|
131
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.select_value("select '2024-01-01'::date").class #=> Date
|
132
|
+
class_attribute :decode_dates, default: false
|
133
|
+
|
136
134
|
NATIVE_DATABASE_TYPES = {
|
137
135
|
primary_key: "bigserial primary key",
|
138
136
|
string: { name: "character varying" },
|
@@ -290,10 +288,6 @@ module ActiveRecord
|
|
290
288
|
{ concurrently: "CONCURRENTLY" }
|
291
289
|
end
|
292
290
|
|
293
|
-
def return_value_after_insert?(column) # :nodoc:
|
294
|
-
column.auto_populated?
|
295
|
-
end
|
296
|
-
|
297
291
|
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
298
292
|
def initialize(connection, max)
|
299
293
|
super(max)
|
@@ -342,6 +336,10 @@ module ActiveRecord
|
|
342
336
|
@use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
|
343
337
|
end
|
344
338
|
|
339
|
+
def connected?
|
340
|
+
!(@raw_connection.nil? || @raw_connection.finished?)
|
341
|
+
end
|
342
|
+
|
345
343
|
# Is this connection alive and ready for queries?
|
346
344
|
def active?
|
347
345
|
@lock.synchronize do
|
@@ -613,7 +611,9 @@ module ActiveRecord
|
|
613
611
|
|
614
612
|
# Returns the version of the connected PostgreSQL server.
|
615
613
|
def get_database_version # :nodoc:
|
616
|
-
|
614
|
+
with_raw_connection do |conn|
|
615
|
+
conn.server_version
|
616
|
+
end
|
617
617
|
end
|
618
618
|
alias :postgresql_version :database_version
|
619
619
|
|
@@ -652,8 +652,8 @@ module ActiveRecord
|
|
652
652
|
m.register_type "int4", Type::Integer.new(limit: 4)
|
653
653
|
m.register_type "int8", Type::Integer.new(limit: 8)
|
654
654
|
m.register_type "oid", OID::Oid.new
|
655
|
-
m.register_type "float4", Type::Float.new
|
656
|
-
m.
|
655
|
+
m.register_type "float4", Type::Float.new(limit: 24)
|
656
|
+
m.register_type "float8", Type::Float.new
|
657
657
|
m.register_type "text", Type::Text.new
|
658
658
|
register_class_with_limit m, "varchar", Type::String
|
659
659
|
m.alias_type "char", "varchar"
|
@@ -777,7 +777,7 @@ module ActiveRecord
|
|
777
777
|
|
778
778
|
case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
|
779
779
|
when nil
|
780
|
-
if exception.message.match?(/connection is closed/i)
|
780
|
+
if exception.message.match?(/connection is closed/i) || exception.message.match?(/no connection to the server/i)
|
781
781
|
ConnectionNotEstablished.new(exception, connection_pool: @pool)
|
782
782
|
elsif exception.is_a?(PG::ConnectionBad)
|
783
783
|
# libpq message style always ends with a newline; the pg gem's internal
|
@@ -889,10 +889,11 @@ module ActiveRecord
|
|
889
889
|
update_typemap_for_default_timezone
|
890
890
|
|
891
891
|
type_casted_binds = type_casted_binds(binds)
|
892
|
-
log(sql, name, binds, type_casted_binds, async: async) do
|
893
|
-
with_raw_connection do |conn|
|
892
|
+
log(sql, name, binds, type_casted_binds, async: async) do |notification_payload|
|
893
|
+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
894
894
|
result = conn.exec_params(sql, type_casted_binds)
|
895
895
|
verified!
|
896
|
+
notification_payload[:row_count] = result.count
|
896
897
|
result
|
897
898
|
end
|
898
899
|
end
|
@@ -903,13 +904,14 @@ module ActiveRecord
|
|
903
904
|
|
904
905
|
update_typemap_for_default_timezone
|
905
906
|
|
906
|
-
with_raw_connection do |conn|
|
907
|
+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
907
908
|
stmt_key = prepare_statement(sql, binds, conn)
|
908
909
|
type_casted_binds = type_casted_binds(binds)
|
909
910
|
|
910
|
-
log(sql, name, binds, type_casted_binds, stmt_key, async: async) do
|
911
|
+
log(sql, name, binds, type_casted_binds, stmt_key, async: async) do |notification_payload|
|
911
912
|
result = conn.exec_prepared(stmt_key, type_casted_binds)
|
912
913
|
verified!
|
914
|
+
notification_payload[:row_count] = result.count
|
913
915
|
result
|
914
916
|
end
|
915
917
|
end
|
@@ -919,7 +921,7 @@ module ActiveRecord
|
|
919
921
|
# Nothing we can do if we are in a transaction because all commands
|
920
922
|
# will raise InFailedSQLTransaction
|
921
923
|
if in_transaction?
|
922
|
-
raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
|
924
|
+
raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message, connection_pool: @pool)
|
923
925
|
else
|
924
926
|
@lock.synchronize do
|
925
927
|
# outside of transactions we can simply flush this query and retry
|
@@ -995,6 +997,8 @@ module ActiveRecord
|
|
995
997
|
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
996
998
|
# This is called by #connect and should not be called manually.
|
997
999
|
def configure_connection
|
1000
|
+
super
|
1001
|
+
|
998
1002
|
if @config[:encoding]
|
999
1003
|
@raw_connection.set_client_encoding(@config[:encoding])
|
1000
1004
|
end
|
@@ -1165,6 +1169,7 @@ module ActiveRecord
|
|
1165
1169
|
"timestamp" => PG::TextDecoder::TimestampUtc,
|
1166
1170
|
"timestamptz" => PG::TextDecoder::TimestampWithTimeZone,
|
1167
1171
|
}
|
1172
|
+
coders_by_name["date"] = PG::TextDecoder::Date if decode_dates
|
1168
1173
|
|
1169
1174
|
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
1170
1175
|
query = <<~SQL % known_coder_types.join(", ")
|
@@ -18,70 +18,62 @@ module ActiveRecord
|
|
18
18
|
@cache_path = cache_path
|
19
19
|
end
|
20
20
|
|
21
|
-
def set_schema_cache(cache)
|
22
|
-
@cache = cache
|
23
|
-
end
|
24
|
-
|
25
21
|
def clear!
|
26
22
|
@cache = empty_cache
|
27
23
|
|
28
24
|
nil
|
29
25
|
end
|
30
26
|
|
31
|
-
def load!(
|
32
|
-
cache(
|
27
|
+
def load!(pool)
|
28
|
+
cache(pool)
|
33
29
|
|
34
30
|
self
|
35
31
|
end
|
36
32
|
|
37
|
-
def primary_keys(
|
38
|
-
cache(
|
33
|
+
def primary_keys(pool, table_name)
|
34
|
+
cache(pool).primary_keys(pool, table_name)
|
39
35
|
end
|
40
36
|
|
41
|
-
def data_source_exists?(
|
42
|
-
cache(
|
37
|
+
def data_source_exists?(pool, name)
|
38
|
+
cache(pool).data_source_exists?(pool, name)
|
43
39
|
end
|
44
40
|
|
45
|
-
def add(
|
46
|
-
cache(
|
41
|
+
def add(pool, name)
|
42
|
+
cache(pool).add(pool, name)
|
47
43
|
end
|
48
44
|
|
49
|
-
def data_sources(
|
50
|
-
cache(
|
45
|
+
def data_sources(pool, name)
|
46
|
+
cache(pool).data_source_exists?(pool, name)
|
51
47
|
end
|
52
48
|
|
53
|
-
def columns(
|
54
|
-
cache(
|
49
|
+
def columns(pool, table_name)
|
50
|
+
cache(pool).columns(pool, table_name)
|
55
51
|
end
|
56
52
|
|
57
|
-
def columns_hash(
|
58
|
-
cache(
|
53
|
+
def columns_hash(pool, table_name)
|
54
|
+
cache(pool).columns_hash(pool, table_name)
|
59
55
|
end
|
60
56
|
|
61
|
-
def columns_hash?(
|
62
|
-
cache(
|
57
|
+
def columns_hash?(pool, table_name)
|
58
|
+
cache(pool).columns_hash?(pool, table_name)
|
63
59
|
end
|
64
60
|
|
65
|
-
def indexes(
|
66
|
-
cache(
|
61
|
+
def indexes(pool, table_name)
|
62
|
+
cache(pool).indexes(pool, table_name)
|
67
63
|
end
|
68
64
|
|
69
|
-
def
|
70
|
-
cache(
|
65
|
+
def version(pool)
|
66
|
+
cache(pool).version(pool)
|
71
67
|
end
|
72
68
|
|
73
|
-
def
|
74
|
-
cache(
|
69
|
+
def size(pool)
|
70
|
+
cache(pool).size
|
75
71
|
end
|
76
72
|
|
77
|
-
def
|
78
|
-
cache(connection).size
|
79
|
-
end
|
80
|
-
|
81
|
-
def clear_data_source_cache!(connection, name)
|
73
|
+
def clear_data_source_cache!(pool, name)
|
82
74
|
return if @cache.nil? && !possible_cache_available?
|
83
75
|
|
84
|
-
cache(
|
76
|
+
cache(pool).clear_data_source_cache!(pool, name)
|
85
77
|
end
|
86
78
|
|
87
79
|
def cached?(table_name)
|
@@ -96,9 +88,9 @@ module ActiveRecord
|
|
96
88
|
@cache&.cached?(table_name)
|
97
89
|
end
|
98
90
|
|
99
|
-
def dump_to(
|
91
|
+
def dump_to(pool, filename)
|
100
92
|
fresh_cache = empty_cache
|
101
|
-
fresh_cache.add_all(
|
93
|
+
fresh_cache.add_all(pool)
|
102
94
|
fresh_cache.dump_to(filename)
|
103
95
|
|
104
96
|
@cache = fresh_cache
|
@@ -111,8 +103,8 @@ module ActiveRecord
|
|
111
103
|
new_cache
|
112
104
|
end
|
113
105
|
|
114
|
-
def cache(
|
115
|
-
@cache ||= load_cache(
|
106
|
+
def cache(pool)
|
107
|
+
@cache ||= load_cache(pool) || empty_cache
|
116
108
|
end
|
117
109
|
|
118
110
|
def possible_cache_available?
|
@@ -121,7 +113,7 @@ module ActiveRecord
|
|
121
113
|
File.file?(@cache_path)
|
122
114
|
end
|
123
115
|
|
124
|
-
def load_cache(
|
116
|
+
def load_cache(pool)
|
125
117
|
# Can't load if schema dumps are disabled
|
126
118
|
return unless possible_cache_available?
|
127
119
|
|
@@ -130,11 +122,13 @@ module ActiveRecord
|
|
130
122
|
|
131
123
|
if self.class.check_schema_cache_dump_version
|
132
124
|
begin
|
133
|
-
|
125
|
+
pool.with_connection do |connection|
|
126
|
+
current_version = connection.schema_version
|
134
127
|
|
135
|
-
|
136
|
-
|
137
|
-
|
128
|
+
if new_cache.version(connection) != current_version
|
129
|
+
warn "Ignoring #{@cache_path} because it has expired. The current schema version is #{current_version}, but the one in the schema cache file is #{new_cache.schema_version}."
|
130
|
+
return
|
131
|
+
end
|
138
132
|
end
|
139
133
|
rescue ActiveRecordError => error
|
140
134
|
warn "Failed to validate the schema cache because of #{error.class}: #{error.message}"
|
@@ -147,9 +141,25 @@ module ActiveRecord
|
|
147
141
|
end
|
148
142
|
|
149
143
|
class BoundSchemaReflection
|
150
|
-
|
144
|
+
class FakePool # :nodoc
|
145
|
+
def initialize(connection)
|
146
|
+
@connection = connection
|
147
|
+
end
|
148
|
+
|
149
|
+
def with_connection
|
150
|
+
yield @connection
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
class << self
|
155
|
+
def for_lone_connection(abstract_schema_reflection, connection) # :nodoc:
|
156
|
+
new(abstract_schema_reflection, FakePool.new(connection))
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def initialize(abstract_schema_reflection, pool)
|
151
161
|
@schema_reflection = abstract_schema_reflection
|
152
|
-
@
|
162
|
+
@pool = pool
|
153
163
|
end
|
154
164
|
|
155
165
|
def clear!
|
@@ -157,7 +167,7 @@ module ActiveRecord
|
|
157
167
|
end
|
158
168
|
|
159
169
|
def load!
|
160
|
-
@schema_reflection.load!(@
|
170
|
+
@schema_reflection.load!(@pool)
|
161
171
|
end
|
162
172
|
|
163
173
|
def cached?(table_name)
|
@@ -165,72 +175,56 @@ module ActiveRecord
|
|
165
175
|
end
|
166
176
|
|
167
177
|
def primary_keys(table_name)
|
168
|
-
@schema_reflection.primary_keys(@
|
178
|
+
@schema_reflection.primary_keys(@pool, table_name)
|
169
179
|
end
|
170
180
|
|
171
181
|
def data_source_exists?(name)
|
172
|
-
@schema_reflection.data_source_exists?(@
|
182
|
+
@schema_reflection.data_source_exists?(@pool, name)
|
173
183
|
end
|
174
184
|
|
175
185
|
def add(name)
|
176
|
-
@schema_reflection.add(@
|
186
|
+
@schema_reflection.add(@pool, name)
|
177
187
|
end
|
178
188
|
|
179
189
|
def data_sources(name)
|
180
|
-
@schema_reflection.data_sources(@
|
190
|
+
@schema_reflection.data_sources(@pool, name)
|
181
191
|
end
|
182
192
|
|
183
193
|
def columns(table_name)
|
184
|
-
@schema_reflection.columns(@
|
194
|
+
@schema_reflection.columns(@pool, table_name)
|
185
195
|
end
|
186
196
|
|
187
197
|
def columns_hash(table_name)
|
188
|
-
@schema_reflection.columns_hash(@
|
198
|
+
@schema_reflection.columns_hash(@pool, table_name)
|
189
199
|
end
|
190
200
|
|
191
201
|
def columns_hash?(table_name)
|
192
|
-
@schema_reflection.columns_hash?(@
|
202
|
+
@schema_reflection.columns_hash?(@pool, table_name)
|
193
203
|
end
|
194
204
|
|
195
205
|
def indexes(table_name)
|
196
|
-
@schema_reflection.indexes(@
|
197
|
-
end
|
198
|
-
|
199
|
-
def database_version # :nodoc:
|
200
|
-
@schema_reflection.database_version(@connection)
|
206
|
+
@schema_reflection.indexes(@pool, table_name)
|
201
207
|
end
|
202
208
|
|
203
209
|
def version
|
204
|
-
@schema_reflection.version(@
|
210
|
+
@schema_reflection.version(@pool)
|
205
211
|
end
|
206
212
|
|
207
213
|
def size
|
208
|
-
@schema_reflection.size(@
|
214
|
+
@schema_reflection.size(@pool)
|
209
215
|
end
|
210
216
|
|
211
217
|
def clear_data_source_cache!(name)
|
212
|
-
@schema_reflection.clear_data_source_cache!(@
|
218
|
+
@schema_reflection.clear_data_source_cache!(@pool, name)
|
213
219
|
end
|
214
220
|
|
215
221
|
def dump_to(filename)
|
216
|
-
@schema_reflection.dump_to(@
|
222
|
+
@schema_reflection.dump_to(@pool, filename)
|
217
223
|
end
|
218
224
|
end
|
219
225
|
|
220
226
|
# = Active Record Connection Adapters Schema Cache
|
221
227
|
class SchemaCache
|
222
|
-
class << self
|
223
|
-
def new(connection)
|
224
|
-
BoundSchemaReflection.new(SchemaReflection.new(nil), connection)
|
225
|
-
end
|
226
|
-
deprecate new: "use ActiveRecord::ConnectionAdapters::SchemaReflection instead", deprecator: ActiveRecord.deprecator
|
227
|
-
|
228
|
-
def load_from(filename) # :nodoc:
|
229
|
-
BoundSchemaReflection.new(SchemaReflection.new(filename), nil)
|
230
|
-
end
|
231
|
-
deprecate load_from: "use ActiveRecord::ConnectionAdapters::SchemaReflection instead", deprecator: ActiveRecord.deprecator
|
232
|
-
end
|
233
|
-
|
234
228
|
def self._load_from(filename) # :nodoc:
|
235
229
|
return unless File.file?(filename)
|
236
230
|
|
@@ -258,13 +252,12 @@ module ActiveRecord
|
|
258
252
|
end
|
259
253
|
private_class_method :read
|
260
254
|
|
261
|
-
def initialize
|
255
|
+
def initialize # :nodoc:
|
262
256
|
@columns = {}
|
263
257
|
@columns_hash = {}
|
264
258
|
@primary_keys = {}
|
265
259
|
@data_sources = {}
|
266
260
|
@indexes = {}
|
267
|
-
@database_version = nil
|
268
261
|
@version = nil
|
269
262
|
end
|
270
263
|
|
@@ -283,17 +276,15 @@ module ActiveRecord
|
|
283
276
|
coder["data_sources"] = @data_sources.sort.to_h
|
284
277
|
coder["indexes"] = @indexes.sort.to_h
|
285
278
|
coder["version"] = @version
|
286
|
-
coder["database_version"] = @database_version
|
287
279
|
end
|
288
280
|
|
289
|
-
def init_with(coder)
|
281
|
+
def init_with(coder) # :nodoc:
|
290
282
|
@columns = coder["columns"]
|
291
283
|
@columns_hash = coder["columns_hash"]
|
292
284
|
@primary_keys = coder["primary_keys"]
|
293
285
|
@data_sources = coder["data_sources"]
|
294
286
|
@indexes = coder["indexes"] || {}
|
295
287
|
@version = coder["version"]
|
296
|
-
@database_version = coder["database_version"]
|
297
288
|
|
298
289
|
unless coder["deduplicated"]
|
299
290
|
derive_columns_hash_and_deduplicate_values
|
@@ -304,78 +295,85 @@ module ActiveRecord
|
|
304
295
|
@columns.key?(table_name)
|
305
296
|
end
|
306
297
|
|
307
|
-
def primary_keys(
|
298
|
+
def primary_keys(pool, table_name)
|
308
299
|
@primary_keys.fetch(table_name) do
|
309
|
-
|
310
|
-
|
300
|
+
pool.with_connection do |connection|
|
301
|
+
if data_source_exists?(pool, table_name)
|
302
|
+
@primary_keys[deep_deduplicate(table_name)] = deep_deduplicate(connection.primary_key(table_name))
|
303
|
+
end
|
311
304
|
end
|
312
305
|
end
|
313
306
|
end
|
314
307
|
|
315
308
|
# A cached lookup for table existence.
|
316
|
-
def data_source_exists?(
|
309
|
+
def data_source_exists?(pool, name)
|
317
310
|
return if ignored_table?(name)
|
318
|
-
|
311
|
+
|
312
|
+
if @data_sources.empty?
|
313
|
+
tables_to_cache(pool).each do |source|
|
314
|
+
@data_sources[source] = true
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
319
318
|
return @data_sources[name] if @data_sources.key? name
|
320
319
|
|
321
|
-
@data_sources[deep_deduplicate(name)] = connection
|
320
|
+
@data_sources[deep_deduplicate(name)] = pool.with_connection do |connection|
|
321
|
+
connection.data_source_exists?(name)
|
322
|
+
end
|
322
323
|
end
|
323
324
|
|
324
325
|
# Add internal cache for table with +table_name+.
|
325
|
-
def add(
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
326
|
+
def add(pool, table_name)
|
327
|
+
pool.with_connection do
|
328
|
+
if data_source_exists?(pool, table_name)
|
329
|
+
primary_keys(pool, table_name)
|
330
|
+
columns(pool, table_name)
|
331
|
+
columns_hash(pool, table_name)
|
332
|
+
indexes(pool, table_name)
|
333
|
+
end
|
331
334
|
end
|
332
335
|
end
|
333
336
|
|
334
|
-
def data_sources(_connection, name) # :nodoc:
|
335
|
-
@data_sources[name]
|
336
|
-
end
|
337
|
-
deprecate data_sources: :data_source_exists?, deprecator: ActiveRecord.deprecator
|
338
|
-
|
339
337
|
# Get the columns for a table
|
340
|
-
def columns(
|
338
|
+
def columns(pool, table_name)
|
341
339
|
if ignored_table?(table_name)
|
342
|
-
raise ActiveRecord::StatementInvalid
|
340
|
+
raise ActiveRecord::StatementInvalid.new("Table '#{table_name}' doesn't exist", connection_pool: pool)
|
343
341
|
end
|
344
342
|
|
345
343
|
@columns.fetch(table_name) do
|
346
|
-
|
344
|
+
pool.with_connection do |connection|
|
345
|
+
@columns[deep_deduplicate(table_name)] = deep_deduplicate(connection.columns(table_name))
|
346
|
+
end
|
347
347
|
end
|
348
348
|
end
|
349
349
|
|
350
350
|
# Get the columns for a table as a hash, key is the column name
|
351
351
|
# value is the column object.
|
352
|
-
def columns_hash(
|
352
|
+
def columns_hash(pool, table_name)
|
353
353
|
@columns_hash.fetch(table_name) do
|
354
|
-
@columns_hash[deep_deduplicate(table_name)] = columns(
|
354
|
+
@columns_hash[deep_deduplicate(table_name)] = columns(pool, table_name).index_by(&:name).freeze
|
355
355
|
end
|
356
356
|
end
|
357
357
|
|
358
358
|
# Checks whether the columns hash is already cached for a table.
|
359
|
-
def columns_hash?(
|
359
|
+
def columns_hash?(_pool, table_name)
|
360
360
|
@columns_hash.key?(table_name)
|
361
361
|
end
|
362
362
|
|
363
|
-
def indexes(
|
363
|
+
def indexes(pool, table_name)
|
364
364
|
@indexes.fetch(table_name) do
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
365
|
+
pool.with_connection do |connection|
|
366
|
+
if data_source_exists?(pool, table_name)
|
367
|
+
@indexes[deep_deduplicate(table_name)] = deep_deduplicate(connection.indexes(table_name))
|
368
|
+
else
|
369
|
+
[]
|
370
|
+
end
|
369
371
|
end
|
370
372
|
end
|
371
373
|
end
|
372
374
|
|
373
|
-
def
|
374
|
-
@
|
375
|
-
end
|
376
|
-
|
377
|
-
def version(connection)
|
378
|
-
@version ||= connection.schema_version
|
375
|
+
def version(pool)
|
376
|
+
@version ||= pool.with_connection(&:schema_version)
|
379
377
|
end
|
380
378
|
|
381
379
|
def schema_version
|
@@ -395,13 +393,14 @@ module ActiveRecord
|
|
395
393
|
@indexes.delete name
|
396
394
|
end
|
397
395
|
|
398
|
-
def add_all(
|
399
|
-
|
400
|
-
|
401
|
-
|
396
|
+
def add_all(pool) # :nodoc:
|
397
|
+
pool.with_connection do
|
398
|
+
tables_to_cache(pool).each do |table|
|
399
|
+
add(pool, table)
|
400
|
+
end
|
402
401
|
|
403
|
-
|
404
|
-
|
402
|
+
version(pool)
|
403
|
+
end
|
405
404
|
end
|
406
405
|
|
407
406
|
def dump_to(filename)
|
@@ -415,20 +414,22 @@ module ActiveRecord
|
|
415
414
|
end
|
416
415
|
|
417
416
|
def marshal_dump # :nodoc:
|
418
|
-
[@version, @columns, {}, @primary_keys, @data_sources, @indexes
|
417
|
+
[@version, @columns, {}, @primary_keys, @data_sources, @indexes]
|
419
418
|
end
|
420
419
|
|
421
420
|
def marshal_load(array) # :nodoc:
|
422
|
-
@version, @columns, _columns_hash, @primary_keys, @data_sources, @indexes,
|
421
|
+
@version, @columns, _columns_hash, @primary_keys, @data_sources, @indexes, _database_version = array
|
423
422
|
@indexes ||= {}
|
424
423
|
|
425
424
|
derive_columns_hash_and_deduplicate_values
|
426
425
|
end
|
427
426
|
|
428
427
|
private
|
429
|
-
def tables_to_cache(
|
430
|
-
|
431
|
-
|
428
|
+
def tables_to_cache(pool)
|
429
|
+
pool.with_connection do |connection|
|
430
|
+
connection.data_sources.reject do |table|
|
431
|
+
ignored_table?(table)
|
432
|
+
end
|
432
433
|
end
|
433
434
|
end
|
434
435
|
|
@@ -459,12 +460,6 @@ module ActiveRecord
|
|
459
460
|
end
|
460
461
|
end
|
461
462
|
|
462
|
-
def prepare_data_sources(connection)
|
463
|
-
tables_to_cache(connection).each do |source|
|
464
|
-
@data_sources[source] = true
|
465
|
-
end
|
466
|
-
end
|
467
|
-
|
468
463
|
def open(filename)
|
469
464
|
FileUtils.mkdir_p(File.dirname(filename))
|
470
465
|
|
@@ -6,10 +6,11 @@ module ActiveRecord
|
|
6
6
|
class Column < ConnectionAdapters::Column # :nodoc:
|
7
7
|
attr_reader :rowid
|
8
8
|
|
9
|
-
def initialize(*, auto_increment: nil, rowid: false, **)
|
9
|
+
def initialize(*, auto_increment: nil, rowid: false, generated_type: nil, **)
|
10
10
|
super
|
11
11
|
@auto_increment = auto_increment
|
12
12
|
@rowid = rowid
|
13
|
+
@generated_type = generated_type
|
13
14
|
end
|
14
15
|
|
15
16
|
def auto_increment?
|
@@ -20,6 +21,18 @@ module ActiveRecord
|
|
20
21
|
auto_increment? || rowid
|
21
22
|
end
|
22
23
|
|
24
|
+
def virtual?
|
25
|
+
!@generated_type.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
def virtual_stored?
|
29
|
+
virtual? && @generated_type == :stored
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_default?
|
33
|
+
super && !virtual?
|
34
|
+
end
|
35
|
+
|
23
36
|
def init_with(coder)
|
24
37
|
@auto_increment = coder["auto_increment"]
|
25
38
|
super
|