activerecord 7.1.3.4 → 7.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +507 -2133
  3. data/README.rdoc +15 -15
  4. data/examples/performance.rb +2 -2
  5. data/lib/active_record/association_relation.rb +1 -1
  6. data/lib/active_record/associations/alias_tracker.rb +25 -19
  7. data/lib/active_record/associations/association.rb +9 -8
  8. data/lib/active_record/associations/belongs_to_association.rb +18 -11
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  10. data/lib/active_record/associations/builder/belongs_to.rb +1 -0
  11. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
  12. data/lib/active_record/associations/builder/has_many.rb +3 -4
  13. data/lib/active_record/associations/builder/has_one.rb +3 -4
  14. data/lib/active_record/associations/collection_association.rb +4 -2
  15. data/lib/active_record/associations/collection_proxy.rb +14 -1
  16. data/lib/active_record/associations/has_many_association.rb +3 -3
  17. data/lib/active_record/associations/has_one_association.rb +2 -2
  18. data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
  19. data/lib/active_record/associations/join_dependency.rb +5 -7
  20. data/lib/active_record/associations/nested_error.rb +47 -0
  21. data/lib/active_record/associations/preloader/association.rb +2 -1
  22. data/lib/active_record/associations/preloader/branch.rb +7 -1
  23. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  24. data/lib/active_record/associations/singular_association.rb +6 -0
  25. data/lib/active_record/associations/through_association.rb +1 -1
  26. data/lib/active_record/associations.rb +34 -11
  27. data/lib/active_record/attribute_assignment.rb +1 -11
  28. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  29. data/lib/active_record/attribute_methods/dirty.rb +1 -1
  30. data/lib/active_record/attribute_methods/primary_key.rb +23 -55
  31. data/lib/active_record/attribute_methods/read.rb +1 -13
  32. data/lib/active_record/attribute_methods/serialization.rb +4 -24
  33. data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -6
  34. data/lib/active_record/attribute_methods.rb +87 -58
  35. data/lib/active_record/attributes.rb +55 -42
  36. data/lib/active_record/autosave_association.rb +14 -30
  37. data/lib/active_record/base.rb +2 -3
  38. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
  39. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
  40. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +248 -58
  41. data/lib/active_record/connection_adapters/abstract/database_statements.rb +35 -18
  42. data/lib/active_record/connection_adapters/abstract/query_cache.rb +160 -75
  43. data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
  44. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  45. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +22 -9
  46. data/lib/active_record/connection_adapters/abstract/transaction.rb +60 -57
  47. data/lib/active_record/connection_adapters/abstract_adapter.rb +32 -61
  48. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +69 -19
  49. data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
  50. data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
  51. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -0
  52. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +11 -5
  53. data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -32
  54. data/lib/active_record/connection_adapters/pool_config.rb +7 -6
  55. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
  56. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  57. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  58. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  59. data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
  60. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -0
  61. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +16 -12
  62. data/lib/active_record/connection_adapters/postgresql_adapter.rb +26 -21
  63. data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
  64. data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
  65. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
  66. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +44 -46
  67. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  68. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
  69. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  70. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +25 -2
  71. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +109 -77
  72. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +12 -6
  73. data/lib/active_record/connection_adapters/trilogy_adapter.rb +32 -65
  74. data/lib/active_record/connection_adapters.rb +121 -0
  75. data/lib/active_record/connection_handling.rb +56 -41
  76. data/lib/active_record/core.rb +59 -38
  77. data/lib/active_record/counter_cache.rb +23 -10
  78. data/lib/active_record/database_configurations/connection_url_resolver.rb +7 -2
  79. data/lib/active_record/database_configurations/database_config.rb +15 -4
  80. data/lib/active_record/database_configurations/hash_config.rb +44 -36
  81. data/lib/active_record/database_configurations/url_config.rb +20 -1
  82. data/lib/active_record/database_configurations.rb +1 -1
  83. data/lib/active_record/delegated_type.rb +30 -6
  84. data/lib/active_record/destroy_association_async_job.rb +1 -1
  85. data/lib/active_record/dynamic_matchers.rb +2 -2
  86. data/lib/active_record/encryption/encryptable_record.rb +2 -2
  87. data/lib/active_record/encryption/encrypted_attribute_type.rb +24 -4
  88. data/lib/active_record/encryption/encryptor.rb +17 -2
  89. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  90. data/lib/active_record/encryption/message_serializer.rb +4 -0
  91. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  92. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  93. data/lib/active_record/encryption/scheme.rb +8 -4
  94. data/lib/active_record/enum.rb +11 -2
  95. data/lib/active_record/errors.rb +16 -11
  96. data/lib/active_record/explain.rb +13 -24
  97. data/lib/active_record/fixtures.rb +37 -31
  98. data/lib/active_record/future_result.rb +17 -4
  99. data/lib/active_record/gem_version.rb +3 -3
  100. data/lib/active_record/inheritance.rb +4 -2
  101. data/lib/active_record/insert_all.rb +18 -15
  102. data/lib/active_record/integration.rb +4 -1
  103. data/lib/active_record/internal_metadata.rb +48 -34
  104. data/lib/active_record/locking/optimistic.rb +8 -7
  105. data/lib/active_record/log_subscriber.rb +0 -21
  106. data/lib/active_record/marshalling.rb +1 -1
  107. data/lib/active_record/message_pack.rb +2 -2
  108. data/lib/active_record/migration/command_recorder.rb +2 -3
  109. data/lib/active_record/migration/compatibility.rb +11 -3
  110. data/lib/active_record/migration/default_strategy.rb +4 -5
  111. data/lib/active_record/migration/pending_migration_connection.rb +2 -2
  112. data/lib/active_record/migration.rb +85 -76
  113. data/lib/active_record/model_schema.rb +34 -69
  114. data/lib/active_record/nested_attributes.rb +11 -3
  115. data/lib/active_record/normalization.rb +3 -7
  116. data/lib/active_record/persistence.rb +32 -354
  117. data/lib/active_record/query_cache.rb +18 -6
  118. data/lib/active_record/query_logs.rb +15 -0
  119. data/lib/active_record/query_logs_formatter.rb +1 -1
  120. data/lib/active_record/querying.rb +21 -9
  121. data/lib/active_record/railtie.rb +52 -64
  122. data/lib/active_record/railties/controller_runtime.rb +13 -4
  123. data/lib/active_record/railties/databases.rake +41 -44
  124. data/lib/active_record/reflection.rb +98 -37
  125. data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
  126. data/lib/active_record/relation/batches.rb +3 -3
  127. data/lib/active_record/relation/calculations.rb +94 -61
  128. data/lib/active_record/relation/delegation.rb +8 -11
  129. data/lib/active_record/relation/finder_methods.rb +16 -2
  130. data/lib/active_record/relation/merger.rb +4 -6
  131. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  132. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +6 -1
  133. data/lib/active_record/relation/predicate_builder.rb +3 -3
  134. data/lib/active_record/relation/query_methods.rb +196 -43
  135. data/lib/active_record/relation/record_fetch_warning.rb +3 -0
  136. data/lib/active_record/relation/spawn_methods.rb +2 -18
  137. data/lib/active_record/relation/where_clause.rb +7 -19
  138. data/lib/active_record/relation.rb +500 -66
  139. data/lib/active_record/result.rb +32 -45
  140. data/lib/active_record/runtime_registry.rb +39 -0
  141. data/lib/active_record/sanitization.rb +24 -19
  142. data/lib/active_record/schema.rb +8 -6
  143. data/lib/active_record/schema_dumper.rb +19 -9
  144. data/lib/active_record/schema_migration.rb +30 -14
  145. data/lib/active_record/signed_id.rb +11 -1
  146. data/lib/active_record/statement_cache.rb +7 -7
  147. data/lib/active_record/table_metadata.rb +1 -10
  148. data/lib/active_record/tasks/database_tasks.rb +70 -42
  149. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  150. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  151. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
  152. data/lib/active_record/test_fixtures.rb +82 -91
  153. data/lib/active_record/testing/query_assertions.rb +121 -0
  154. data/lib/active_record/timestamp.rb +4 -2
  155. data/lib/active_record/token_for.rb +22 -12
  156. data/lib/active_record/touch_later.rb +1 -1
  157. data/lib/active_record/transaction.rb +68 -0
  158. data/lib/active_record/transactions.rb +43 -14
  159. data/lib/active_record/translation.rb +0 -2
  160. data/lib/active_record/type/serialized.rb +1 -3
  161. data/lib/active_record/type_caster/connection.rb +4 -4
  162. data/lib/active_record/validations/associated.rb +9 -3
  163. data/lib/active_record/validations/uniqueness.rb +14 -10
  164. data/lib/active_record/validations.rb +4 -1
  165. data/lib/active_record.rb +149 -40
  166. data/lib/arel/alias_predication.rb +1 -1
  167. data/lib/arel/collectors/bind.rb +2 -0
  168. data/lib/arel/collectors/composite.rb +7 -0
  169. data/lib/arel/collectors/sql_string.rb +1 -1
  170. data/lib/arel/collectors/substitute_binds.rb +1 -1
  171. data/lib/arel/nodes/binary.rb +0 -6
  172. data/lib/arel/nodes/bound_sql_literal.rb +9 -5
  173. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  174. data/lib/arel/nodes/node.rb +4 -3
  175. data/lib/arel/nodes/sql_literal.rb +7 -0
  176. data/lib/arel/nodes.rb +2 -2
  177. data/lib/arel/predications.rb +1 -1
  178. data/lib/arel/select_manager.rb +1 -1
  179. data/lib/arel/tree_manager.rb +8 -3
  180. data/lib/arel/update_manager.rb +2 -1
  181. data/lib/arel/visitors/dot.rb +1 -0
  182. data/lib/arel/visitors/mysql.rb +9 -4
  183. data/lib/arel/visitors/postgresql.rb +1 -12
  184. data/lib/arel/visitors/to_sql.rb +31 -17
  185. data/lib/arel.rb +7 -3
  186. metadata +17 -12
@@ -112,7 +112,7 @@ module ActiveRecord
112
112
 
113
113
  orders = {}
114
114
  opclasses = {}
115
- include_columns = include ? include.split(",").map(&:strip) : []
115
+ include_columns = include ? include.split(",").map { |c| Utils.unquote_identifier(c.strip.gsub('""', '"')) } : []
116
116
 
117
117
  if indkey.include?(0)
118
118
  columns = expressions
@@ -209,8 +209,16 @@ module ActiveRecord
209
209
  end
210
210
 
211
211
  # Creates a schema for the given schema name.
212
- def create_schema(schema_name)
213
- execute "CREATE SCHEMA #{quote_schema_name(schema_name)}"
212
+ def create_schema(schema_name, force: nil, if_not_exists: nil)
213
+ if force && if_not_exists
214
+ raise ArgumentError, "Options `:force` and `:if_not_exists` cannot be used simultaneously."
215
+ end
216
+
217
+ if force
218
+ drop_schema(schema_name, if_exists: true)
219
+ end
220
+
221
+ execute("CREATE SCHEMA#{' IF NOT EXISTS' if if_not_exists} #{quote_schema_name(schema_name)}")
214
222
  end
215
223
 
216
224
  # Drops the schema for the given schema name.
@@ -400,7 +408,7 @@ module ActiveRecord
400
408
  execute "ALTER TABLE #{seq.quoted} RENAME TO #{quote_table_name(new_seq)}"
401
409
  end
402
410
  end
403
- rename_table_indexes(table_name, new_name)
411
+ rename_table_indexes(table_name, new_name, **options)
404
412
  end
405
413
 
406
414
  def add_column(table_name, column_name, type, **options) # :nodoc:
@@ -522,14 +530,6 @@ module ActiveRecord
522
530
  end
523
531
 
524
532
  def add_foreign_key(from_table, to_table, **options)
525
- if options[:deferrable] == true
526
- ActiveRecord.deprecator.warn(<<~MSG)
527
- `deferrable: true` is deprecated in favor of `deferrable: :immediate`, and will be removed in Rails 7.2.
528
- MSG
529
-
530
- options[:deferrable] = :immediate
531
- end
532
-
533
533
  assert_valid_deferrable(options[:deferrable])
534
534
 
535
535
  super
@@ -690,6 +690,10 @@ module ActiveRecord
690
690
  # The constraint name. Defaults to <tt>excl_rails_<identifier></tt>.
691
691
  # [<tt>:deferrable</tt>]
692
692
  # Specify whether or not the exclusion constraint should be deferrable. Valid values are +false+ or +:immediate+ or +:deferred+ to specify the default behavior. Defaults to +false+.
693
+ # [<tt>:using</tt>]
694
+ # Specify which index method to use when creating this exclusion constraint (e.g. +:btree+, +:gist+ etc).
695
+ # [<tt>:where</tt>]
696
+ # Specify an exclusion constraint on a subset of the table (internally PostgreSQL creates a partial index for this).
693
697
  def add_exclusion_constraint(table_name, expression, **options)
694
698
  options = exclusion_constraint_options(table_name, expression, options)
695
699
  at = create_alter_table(table_name)
@@ -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
- valid_raw_connection.server_version
614
+ with_raw_connection do |conn|
615
+ conn.server_version
616
+ end
617
617
  end
618
618
  alias :postgresql_version :database_version
619
619
 
@@ -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!(connection)
32
- cache(connection)
27
+ def load!(pool)
28
+ cache(pool)
33
29
 
34
30
  self
35
31
  end
36
32
 
37
- def primary_keys(connection, table_name)
38
- cache(connection).primary_keys(connection, table_name)
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?(connection, name)
42
- cache(connection).data_source_exists?(connection, name)
37
+ def data_source_exists?(pool, name)
38
+ cache(pool).data_source_exists?(pool, name)
43
39
  end
44
40
 
45
- def add(connection, name)
46
- cache(connection).add(connection, name)
41
+ def add(pool, name)
42
+ cache(pool).add(pool, name)
47
43
  end
48
44
 
49
- def data_sources(connection, name)
50
- cache(connection).data_sources(connection, name)
45
+ def data_sources(pool, name)
46
+ cache(pool).data_source_exists?(pool, name)
51
47
  end
52
48
 
53
- def columns(connection, table_name)
54
- cache(connection).columns(connection, table_name)
49
+ def columns(pool, table_name)
50
+ cache(pool).columns(pool, table_name)
55
51
  end
56
52
 
57
- def columns_hash(connection, table_name)
58
- cache(connection).columns_hash(connection, table_name)
53
+ def columns_hash(pool, table_name)
54
+ cache(pool).columns_hash(pool, table_name)
59
55
  end
60
56
 
61
- def columns_hash?(connection, table_name)
62
- cache(connection).columns_hash?(connection, table_name)
57
+ def columns_hash?(pool, table_name)
58
+ cache(pool).columns_hash?(pool, table_name)
63
59
  end
64
60
 
65
- def indexes(connection, table_name)
66
- cache(connection).indexes(connection, table_name)
61
+ def indexes(pool, table_name)
62
+ cache(pool).indexes(pool, table_name)
67
63
  end
68
64
 
69
- def database_version(connection) # :nodoc:
70
- cache(connection).database_version(connection)
65
+ def version(pool)
66
+ cache(pool).version(pool)
71
67
  end
72
68
 
73
- def version(connection)
74
- cache(connection).version(connection)
69
+ def size(pool)
70
+ cache(pool).size
75
71
  end
76
72
 
77
- def size(connection)
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(connection).clear_data_source_cache!(connection, name)
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(connection, filename)
91
+ def dump_to(pool, filename)
100
92
  fresh_cache = empty_cache
101
- fresh_cache.add_all(connection)
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(connection)
115
- @cache ||= load_cache(connection) || empty_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(connection)
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
- current_version = connection.schema_version
125
+ pool.with_connection do |connection|
126
+ current_version = connection.schema_version
134
127
 
135
- if new_cache.version(connection) != current_version
136
- 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}."
137
- return
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
- def initialize(abstract_schema_reflection, connection)
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
- @connection = connection
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!(@connection)
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(@connection, table_name)
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?(@connection, name)
182
+ @schema_reflection.data_source_exists?(@pool, name)
173
183
  end
174
184
 
175
185
  def add(name)
176
- @schema_reflection.add(@connection, name)
186
+ @schema_reflection.add(@pool, name)
177
187
  end
178
188
 
179
189
  def data_sources(name)
180
- @schema_reflection.data_sources(@connection, name)
190
+ @schema_reflection.data_sources(@pool, name)
181
191
  end
182
192
 
183
193
  def columns(table_name)
184
- @schema_reflection.columns(@connection, table_name)
194
+ @schema_reflection.columns(@pool, table_name)
185
195
  end
186
196
 
187
197
  def columns_hash(table_name)
188
- @schema_reflection.columns_hash(@connection, table_name)
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?(@connection, table_name)
202
+ @schema_reflection.columns_hash?(@pool, table_name)
193
203
  end
194
204
 
195
205
  def indexes(table_name)
196
- @schema_reflection.indexes(@connection, table_name)
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(@connection)
210
+ @schema_reflection.version(@pool)
205
211
  end
206
212
 
207
213
  def size
208
- @schema_reflection.size(@connection)
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!(@connection, name)
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(@connection, filename)
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(connection, table_name)
298
+ def primary_keys(pool, table_name)
308
299
  @primary_keys.fetch(table_name) do
309
- if data_source_exists?(connection, table_name)
310
- @primary_keys[deep_deduplicate(table_name)] = deep_deduplicate(connection.primary_key(table_name))
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?(connection, name)
309
+ def data_source_exists?(pool, name)
317
310
  return if ignored_table?(name)
318
- prepare_data_sources(connection) if @data_sources.empty?
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.data_source_exists?(name)
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(connection, table_name)
326
- if data_source_exists?(connection, table_name)
327
- primary_keys(connection, table_name)
328
- columns(connection, table_name)
329
- columns_hash(connection, table_name)
330
- indexes(connection, table_name)
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(connection, table_name)
338
+ def columns(pool, table_name)
341
339
  if ignored_table?(table_name)
342
- raise ActiveRecord::StatementInvalid, "Table '#{table_name}' doesn't exist"
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
- @columns[deep_deduplicate(table_name)] = deep_deduplicate(connection.columns(table_name))
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(connection, table_name)
352
+ def columns_hash(pool, table_name)
353
353
  @columns_hash.fetch(table_name) do
354
- @columns_hash[deep_deduplicate(table_name)] = columns(connection, table_name).index_by(&:name).freeze
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?(connection, table_name)
359
+ def columns_hash?(_pool, table_name)
360
360
  @columns_hash.key?(table_name)
361
361
  end
362
362
 
363
- def indexes(connection, table_name)
363
+ def indexes(pool, table_name)
364
364
  @indexes.fetch(table_name) do
365
- if data_source_exists?(connection, table_name)
366
- @indexes[deep_deduplicate(table_name)] = deep_deduplicate(connection.indexes(table_name))
367
- else
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 database_version(connection) # :nodoc:
374
- @database_version ||= connection.get_database_version
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(connection) # :nodoc:
399
- tables_to_cache(connection).each do |table|
400
- add(connection, table)
401
- end
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
- version(connection)
404
- database_version(connection)
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, @database_version]
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, @database_version = array
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(connection)
430
- connection.data_sources.reject do |table|
431
- ignored_table?(table)
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