activerecord 7.1.5.2 → 8.1.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.
Files changed (244) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +567 -2443
  3. data/README.rdoc +16 -16
  4. data/examples/performance.rb +2 -2
  5. data/lib/active_record/association_relation.rb +3 -2
  6. data/lib/active_record/associations/alias_tracker.rb +31 -23
  7. data/lib/active_record/associations/association.rb +43 -12
  8. data/lib/active_record/associations/belongs_to_association.rb +31 -8
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  10. data/lib/active_record/associations/builder/association.rb +23 -11
  11. data/lib/active_record/associations/builder/belongs_to.rb +18 -4
  12. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  13. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
  14. data/lib/active_record/associations/builder/has_many.rb +3 -4
  15. data/lib/active_record/associations/builder/has_one.rb +3 -4
  16. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  17. data/lib/active_record/associations/collection_association.rb +17 -9
  18. data/lib/active_record/associations/collection_proxy.rb +36 -5
  19. data/lib/active_record/associations/deprecation.rb +88 -0
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  21. data/lib/active_record/associations/errors.rb +268 -0
  22. data/lib/active_record/associations/has_many_association.rb +1 -1
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -3
  24. data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
  25. data/lib/active_record/associations/join_dependency.rb +4 -2
  26. data/lib/active_record/associations/nested_error.rb +47 -0
  27. data/lib/active_record/associations/preloader/association.rb +4 -3
  28. data/lib/active_record/associations/preloader/batch.rb +7 -1
  29. data/lib/active_record/associations/preloader/branch.rb +8 -1
  30. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  31. data/lib/active_record/associations/singular_association.rb +14 -3
  32. data/lib/active_record/associations/through_association.rb +1 -1
  33. data/lib/active_record/associations.rb +250 -315
  34. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  35. data/lib/active_record/attribute_assignment.rb +0 -2
  36. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  37. data/lib/active_record/attribute_methods/primary_key.rb +25 -61
  38. data/lib/active_record/attribute_methods/query.rb +34 -0
  39. data/lib/active_record/attribute_methods/read.rb +1 -13
  40. data/lib/active_record/attribute_methods/serialization.rb +20 -27
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +19 -20
  42. data/lib/active_record/attribute_methods.rb +71 -75
  43. data/lib/active_record/attributes.rb +96 -68
  44. data/lib/active_record/autosave_association.rb +93 -58
  45. data/lib/active_record/base.rb +5 -7
  46. data/lib/active_record/callbacks.rb +1 -1
  47. data/lib/active_record/coders/json.rb +14 -5
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +50 -126
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +52 -13
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +681 -135
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +165 -86
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +226 -78
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -114
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +136 -34
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +163 -68
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -129
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +112 -63
  62. data/lib/active_record/connection_adapters/column.rb +17 -4
  63. data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -3
  64. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
  65. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  66. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
  67. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +79 -46
  68. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +97 -101
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +14 -33
  70. data/lib/active_record/connection_adapters/pool_config.rb +14 -13
  71. data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
  72. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +98 -44
  73. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
  74. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  75. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  77. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  78. data/lib/active_record/connection_adapters/postgresql/quoting.rb +79 -68
  79. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  80. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
  81. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +44 -41
  82. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
  83. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +155 -75
  84. data/lib/active_record/connection_adapters/postgresql_adapter.rb +104 -121
  85. data/lib/active_record/connection_adapters/schema_cache.rb +126 -133
  86. data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
  87. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +91 -95
  88. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -54
  89. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
  90. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
  91. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +43 -2
  92. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -15
  93. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +231 -111
  94. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  95. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +40 -69
  96. data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
  97. data/lib/active_record/connection_adapters.rb +66 -0
  98. data/lib/active_record/connection_handling.rb +88 -46
  99. data/lib/active_record/core.rb +142 -58
  100. data/lib/active_record/counter_cache.rb +52 -18
  101. data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
  102. data/lib/active_record/database_configurations/database_config.rb +28 -5
  103. data/lib/active_record/database_configurations/hash_config.rb +103 -41
  104. data/lib/active_record/database_configurations/url_config.rb +30 -1
  105. data/lib/active_record/database_configurations.rb +8 -4
  106. data/lib/active_record/delegated_type.rb +43 -19
  107. data/lib/active_record/dynamic_matchers.rb +56 -71
  108. data/lib/active_record/encryption/config.rb +3 -1
  109. data/lib/active_record/encryption/encryptable_record.rb +12 -12
  110. data/lib/active_record/encryption/encrypted_attribute_type.rb +35 -6
  111. data/lib/active_record/encryption/encryptor.rb +58 -22
  112. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  113. data/lib/active_record/encryption/key_provider.rb +1 -1
  114. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  115. data/lib/active_record/encryption/message_serializer.rb +4 -0
  116. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  117. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  118. data/lib/active_record/encryption/scheme.rb +9 -2
  119. data/lib/active_record/enum.rb +57 -36
  120. data/lib/active_record/errors.rb +76 -26
  121. data/lib/active_record/explain.rb +14 -25
  122. data/lib/active_record/explain_registry.rb +51 -2
  123. data/lib/active_record/filter_attribute_handler.rb +73 -0
  124. data/lib/active_record/fixture_set/table_row.rb +19 -2
  125. data/lib/active_record/fixtures.rb +39 -35
  126. data/lib/active_record/future_result.rb +21 -13
  127. data/lib/active_record/gem_version.rb +3 -3
  128. data/lib/active_record/inheritance.rb +5 -3
  129. data/lib/active_record/insert_all.rb +28 -20
  130. data/lib/active_record/integration.rb +4 -1
  131. data/lib/active_record/internal_metadata.rb +48 -34
  132. data/lib/active_record/locking/optimistic.rb +15 -7
  133. data/lib/active_record/locking/pessimistic.rb +5 -0
  134. data/lib/active_record/log_subscriber.rb +3 -34
  135. data/lib/active_record/message_pack.rb +1 -1
  136. data/lib/active_record/middleware/shard_selector.rb +34 -17
  137. data/lib/active_record/migration/command_recorder.rb +46 -14
  138. data/lib/active_record/migration/compatibility.rb +40 -25
  139. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  140. data/lib/active_record/migration/default_strategy.rb +4 -5
  141. data/lib/active_record/migration/pending_migration_connection.rb +2 -2
  142. data/lib/active_record/migration.rb +119 -103
  143. data/lib/active_record/model_schema.rb +66 -78
  144. data/lib/active_record/nested_attributes.rb +17 -9
  145. data/lib/active_record/persistence.rb +161 -454
  146. data/lib/active_record/query_cache.rb +33 -15
  147. data/lib/active_record/query_logs.rb +106 -39
  148. data/lib/active_record/query_logs_formatter.rb +17 -28
  149. data/lib/active_record/querying.rb +28 -16
  150. data/lib/active_record/railtie.rb +61 -74
  151. data/lib/active_record/railties/controller_runtime.rb +19 -5
  152. data/lib/active_record/railties/databases.rake +64 -78
  153. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  154. data/lib/active_record/railties/job_runtime.rb +10 -11
  155. data/lib/active_record/reflection.rb +147 -53
  156. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  157. data/lib/active_record/relation/batches.rb +153 -73
  158. data/lib/active_record/relation/calculations.rb +146 -96
  159. data/lib/active_record/relation/delegation.rb +30 -23
  160. data/lib/active_record/relation/finder_methods.rb +64 -34
  161. data/lib/active_record/relation/merger.rb +12 -14
  162. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  163. data/lib/active_record/relation/predicate_builder/association_query_value.rb +19 -11
  164. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
  165. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  166. data/lib/active_record/relation/predicate_builder.rb +25 -10
  167. data/lib/active_record/relation/query_attribute.rb +4 -2
  168. data/lib/active_record/relation/query_methods.rb +351 -124
  169. data/lib/active_record/relation/spawn_methods.rb +9 -25
  170. data/lib/active_record/relation/where_clause.rb +17 -30
  171. data/lib/active_record/relation.rb +590 -124
  172. data/lib/active_record/result.rb +131 -59
  173. data/lib/active_record/runtime_registry.rb +44 -21
  174. data/lib/active_record/sanitization.rb +33 -25
  175. data/lib/active_record/schema.rb +8 -6
  176. data/lib/active_record/schema_dumper.rb +66 -31
  177. data/lib/active_record/schema_migration.rb +31 -14
  178. data/lib/active_record/scoping/named.rb +6 -2
  179. data/lib/active_record/scoping.rb +0 -1
  180. data/lib/active_record/secure_token.rb +3 -3
  181. data/lib/active_record/signed_id.rb +68 -20
  182. data/lib/active_record/statement_cache.rb +29 -25
  183. data/lib/active_record/store.rb +51 -22
  184. data/lib/active_record/structured_event_subscriber.rb +85 -0
  185. data/lib/active_record/table_metadata.rb +7 -33
  186. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  187. data/lib/active_record/tasks/database_tasks.rb +118 -90
  188. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
  189. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
  190. data/lib/active_record/tasks/sqlite_database_tasks.rb +17 -28
  191. data/lib/active_record/test_databases.rb +14 -4
  192. data/lib/active_record/test_fixtures.rb +123 -89
  193. data/lib/active_record/testing/query_assertions.rb +127 -0
  194. data/lib/active_record/timestamp.rb +6 -4
  195. data/lib/active_record/token_for.rb +22 -12
  196. data/lib/active_record/touch_later.rb +1 -1
  197. data/lib/active_record/transaction.rb +129 -0
  198. data/lib/active_record/transactions.rb +97 -18
  199. data/lib/active_record/translation.rb +0 -2
  200. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  201. data/lib/active_record/type/internal/timezone.rb +7 -0
  202. data/lib/active_record/type/json.rb +15 -2
  203. data/lib/active_record/type/serialized.rb +12 -7
  204. data/lib/active_record/type/type_map.rb +1 -1
  205. data/lib/active_record/type_caster/connection.rb +5 -4
  206. data/lib/active_record/validations/associated.rb +10 -4
  207. data/lib/active_record/validations/uniqueness.rb +23 -18
  208. data/lib/active_record/validations.rb +4 -1
  209. data/lib/active_record.rb +203 -59
  210. data/lib/arel/alias_predication.rb +3 -1
  211. data/lib/arel/collectors/bind.rb +4 -2
  212. data/lib/arel/collectors/composite.rb +7 -0
  213. data/lib/arel/collectors/sql_string.rb +2 -2
  214. data/lib/arel/collectors/substitute_binds.rb +3 -3
  215. data/lib/arel/crud.rb +8 -11
  216. data/lib/arel/delete_manager.rb +5 -0
  217. data/lib/arel/nodes/binary.rb +1 -7
  218. data/lib/arel/nodes/bound_sql_literal.rb +9 -5
  219. data/lib/arel/nodes/count.rb +2 -2
  220. data/lib/arel/nodes/delete_statement.rb +4 -2
  221. data/lib/arel/nodes/function.rb +4 -10
  222. data/lib/arel/nodes/named_function.rb +2 -2
  223. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  224. data/lib/arel/nodes/node.rb +6 -5
  225. data/lib/arel/nodes/sql_literal.rb +8 -1
  226. data/lib/arel/nodes/update_statement.rb +4 -2
  227. data/lib/arel/nodes.rb +2 -4
  228. data/lib/arel/predications.rb +1 -1
  229. data/lib/arel/select_manager.rb +14 -5
  230. data/lib/arel/table.rb +3 -7
  231. data/lib/arel/tree_manager.rb +3 -2
  232. data/lib/arel/update_manager.rb +7 -1
  233. data/lib/arel/visitors/dot.rb +3 -3
  234. data/lib/arel/visitors/mysql.rb +9 -4
  235. data/lib/arel/visitors/postgresql.rb +56 -12
  236. data/lib/arel/visitors/sqlite.rb +80 -8
  237. data/lib/arel/visitors/to_sql.rb +34 -37
  238. data/lib/arel.rb +10 -4
  239. data/lib/rails/generators/active_record/application_record/USAGE +1 -1
  240. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  241. metadata +23 -14
  242. data/lib/active_record/explain_subscriber.rb +0 -34
  243. data/lib/active_record/normalization.rb +0 -167
  244. data/lib/active_record/relation/record_fetch_warning.rb +0 -49
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "set"
4
3
  require "active_record/connection_adapters/sql_type_metadata"
5
4
  require "active_record/connection_adapters/abstract/schema_dumper"
6
5
  require "active_record/connection_adapters/abstract/schema_creation"
7
6
  require "active_support/concurrency/null_lock"
8
7
  require "active_support/concurrency/load_interlock_aware_monitor"
8
+ require "active_support/concurrency/thread_monitor"
9
9
  require "arel/collectors/bind"
10
10
  require "arel/collectors/composite"
11
11
  require "arel/collectors/sql_string"
@@ -23,7 +23,7 @@ module ActiveRecord
23
23
  # and +:limit+ options, etc.
24
24
  #
25
25
  # All the concrete database adapters follow the interface laid down in this class.
26
- # {ActiveRecord::Base.connection}[rdoc-ref:ConnectionHandling#connection] returns an AbstractAdapter object, which
26
+ # {ActiveRecord::Base.lease_connection}[rdoc-ref:ConnectionHandling#lease_connection] returns an AbstractAdapter object, which
27
27
  # you can use.
28
28
  #
29
29
  # Most of the methods in the adapter are useful during migrations. Most
@@ -43,17 +43,21 @@ module ActiveRecord
43
43
 
44
44
  attr_reader :pool
45
45
  attr_reader :visitor, :owner, :logger, :lock
46
+ attr_reader :allow_preconnect # :nodoc:
47
+ attr_accessor :pinned # :nodoc:
46
48
  alias :in_use? :owner
47
49
 
48
50
  def pool=(value)
49
51
  return if value.eql?(@pool)
50
52
  @schema_cache = nil
51
53
  @pool = value
52
-
53
- @pool.schema_reflection.load!(self) if ActiveRecord.lazily_load_schema_cache
54
54
  end
55
55
 
56
- set_callback :checkin, :after, :enable_lazy_transactions!
56
+ def allow_preconnect=(value) # :nodoc:
57
+ @lock.synchronize do
58
+ @allow_preconnect = value
59
+ end
60
+ end
57
61
 
58
62
  def self.type_cast_config_to_integer(config)
59
63
  if config.is_a?(Integer)
@@ -122,7 +126,7 @@ module ActiveRecord
122
126
 
123
127
  # Opens a database console session.
124
128
  def self.dbconsole(config, options = {})
125
- raise NotImplementedError
129
+ raise NotImplementedError.new("#{self.class} should define `dbconsole` that accepts a db config and options to implement connecting to the db console")
126
130
  end
127
131
 
128
132
  def initialize(config_or_deprecated_connection, deprecated_logger = nil, deprecated_connection_options = nil, deprecated_config = nil) # :nodoc:
@@ -130,18 +134,20 @@ module ActiveRecord
130
134
 
131
135
  @raw_connection = nil
132
136
  @unconfigured_connection = nil
137
+ @connected_since = nil
133
138
 
134
139
  if config_or_deprecated_connection.is_a?(Hash)
135
140
  @config = config_or_deprecated_connection.symbolize_keys
136
141
  @logger = ActiveRecord::Base.logger
137
142
 
138
143
  if deprecated_logger || deprecated_connection_options || deprecated_config
139
- raise ArgumentError, "when initializing an ActiveRecord adapter with a config hash, that should be the only argument"
144
+ raise ArgumentError, "when initializing an Active Record adapter with a config hash, that should be the only argument"
140
145
  end
141
146
  else
142
147
  # Soft-deprecated for now; we'll probably warn in future.
143
148
 
144
149
  @unconfigured_connection = config_or_deprecated_connection
150
+ @connected_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
145
151
  @logger = deprecated_logger || ActiveRecord::Base.logger
146
152
  if deprecated_config
147
153
  @config = (deprecated_config || {}).symbolize_keys
@@ -153,9 +159,10 @@ module ActiveRecord
153
159
  end
154
160
 
155
161
  @owner = nil
156
- @instrumenter = ActiveSupport::Notifications.instrumenter
162
+ @pinned = false
157
163
  @pool = ActiveRecord::ConnectionAdapters::NullPool.new
158
164
  @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
165
+ @allow_preconnect = false
159
166
  @visitor = arel_visitor
160
167
  @statements = build_statement_pool
161
168
  self.lock_thread = nil
@@ -171,58 +178,54 @@ module ActiveRecord
171
178
  @default_timezone = self.class.validate_default_timezone(@config[:default_timezone])
172
179
 
173
180
  @raw_connection_dirty = false
181
+ @last_activity = nil
174
182
  @verified = false
183
+
184
+ @pool_jitter = rand * max_jitter
175
185
  end
176
186
 
177
- THREAD_LOCK = ActiveSupport::Concurrency::ThreadLoadInterlockAwareMonitor.new
178
- private_constant :THREAD_LOCK
187
+ def inspect # :nodoc:
188
+ name_field = " name=#{pool.db_config.name.inspect}" unless pool.db_config.name == "primary"
189
+ shard_field = " shard=#{shard.inspect}" unless shard == :default
179
190
 
180
- FIBER_LOCK = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
181
- private_constant :FIBER_LOCK
191
+ "#<#{self.class.name}:#{'%#016x' % (object_id << 1)} env_name=#{pool.db_config.env_name.inspect}#{name_field} role=#{role.inspect}#{shard_field}>"
192
+ end
182
193
 
183
194
  def lock_thread=(lock_thread) # :nodoc:
184
195
  @lock =
185
196
  case lock_thread
186
197
  when Thread
187
- THREAD_LOCK
198
+ ActiveSupport::Concurrency::ThreadMonitor.new
188
199
  when Fiber
189
- FIBER_LOCK
200
+ ::Monitor.new
190
201
  else
191
202
  ActiveSupport::Concurrency::NullLock
192
203
  end
193
204
  end
194
205
 
195
- EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
196
- EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze # :nodoc:
197
- private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
198
- def with_instrumenter(instrumenter, &block) # :nodoc:
199
- Thread.handle_interrupt(EXCEPTION_NEVER) do
200
- previous_instrumenter = @instrumenter
201
- @instrumenter = instrumenter
202
- Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
203
- ensure
204
- @instrumenter = previous_instrumenter
206
+ def ensure_writes_are_allowed(sql) # :nodoc:
207
+ if preventing_writes?
208
+ raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
205
209
  end
206
210
  end
207
211
 
208
- def check_if_write_query(sql) # :nodoc:
209
- if preventing_writes? && write_query?(sql)
210
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
211
- end
212
+ MAX_JITTER = 0.0..1.0 # :nodoc:
213
+ def max_jitter
214
+ (@config[:pool_jitter] || 0.2).to_f.clamp(MAX_JITTER)
212
215
  end
213
216
 
214
217
  def replica?
215
218
  @config[:replica] || false
216
219
  end
217
220
 
218
- def use_metadata_table?
219
- @config.fetch(:use_metadata_table, true)
220
- end
221
-
222
221
  def connection_retries
223
222
  (@config[:connection_retries] || 1).to_i
224
223
  end
225
224
 
225
+ def verify_timeout
226
+ (@config[:verify_timeout] || 2).to_i
227
+ end
228
+
226
229
  def retry_deadline
227
230
  if @config[:retry_deadline]
228
231
  @config[:retry_deadline].to_f
@@ -241,25 +244,9 @@ module ActiveRecord
241
244
  # the value of +current_preventing_writes+.
242
245
  def preventing_writes?
243
246
  return true if replica?
244
- return false if connection_class.nil?
245
-
246
- connection_class.current_preventing_writes
247
- end
248
-
249
- def migrations_paths # :nodoc:
250
- @config[:migrations_paths] || Migrator.migrations_paths
251
- end
252
-
253
- def migration_context # :nodoc:
254
- MigrationContext.new(migrations_paths, schema_migration, internal_metadata)
255
- end
256
-
257
- def schema_migration # :nodoc:
258
- SchemaMigration.new(self)
259
- end
247
+ return false if connection_descriptor.nil?
260
248
 
261
- def internal_metadata # :nodoc:
262
- InternalMetadata.new(self)
249
+ connection_descriptor.current_preventing_writes
263
250
  end
264
251
 
265
252
  def prepared_statements?
@@ -291,7 +278,11 @@ module ActiveRecord
291
278
  end
292
279
 
293
280
  def valid_type?(type) # :nodoc:
294
- !native_database_types[type].nil?
281
+ self.class.valid_type?(type)
282
+ end
283
+
284
+ def native_database_types # :nodoc:
285
+ self.class.native_database_types
295
286
  end
296
287
 
297
288
  # this method must only be called while holding connection pool's mutex
@@ -310,8 +301,8 @@ module ActiveRecord
310
301
  @owner = ActiveSupport::IsolatedExecutionState.context
311
302
  end
312
303
 
313
- def connection_class # :nodoc:
314
- @pool.connection_class
304
+ def connection_descriptor # :nodoc:
305
+ @pool.connection_descriptor
315
306
  end
316
307
 
317
308
  # The role (e.g. +:writing+) for the current connection. In a
@@ -327,11 +318,15 @@ module ActiveRecord
327
318
  end
328
319
 
329
320
  def schema_cache
330
- @schema_cache ||= BoundSchemaReflection.new(@pool.schema_reflection, self)
321
+ @pool.schema_cache || (@schema_cache ||= BoundSchemaReflection.for_lone_connection(@pool.schema_reflection, self))
322
+ end
323
+
324
+ def pool_jitter(duration)
325
+ duration * (1.0 - @pool_jitter)
331
326
  end
332
327
 
333
328
  # this method must only be called while holding connection pool's mutex
334
- def expire
329
+ def expire(update_idle = true) # :nodoc:
335
330
  if in_use?
336
331
  if @owner != ActiveSupport::IsolatedExecutionState.context
337
332
  raise ActiveRecordError, "Cannot expire connection, " \
@@ -339,8 +334,12 @@ module ActiveRecord
339
334
  "Current thread: #{ActiveSupport::IsolatedExecutionState.context}."
340
335
  end
341
336
 
342
- @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
343
- @owner = nil
337
+ _run_checkin_callbacks do
338
+ @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC) if update_idle
339
+ @owner = nil
340
+ enable_lazy_transactions!
341
+ unset_query_cache!
342
+ end
344
343
  else
345
344
  raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
346
345
  end
@@ -365,6 +364,28 @@ module ActiveRecord
365
364
  Process.clock_gettime(Process::CLOCK_MONOTONIC) - @idle_since
366
365
  end
367
366
 
367
+ # Seconds since this connection last communicated with the server
368
+ def seconds_since_last_activity # :nodoc:
369
+ if @raw_connection && @last_activity
370
+ Process.clock_gettime(Process::CLOCK_MONOTONIC) - @last_activity
371
+ end
372
+ end
373
+
374
+ # Seconds since this connection was established. nil if not
375
+ # connected; infinity if the connection has been explicitly
376
+ # retired.
377
+ def connection_age # :nodoc:
378
+ if @raw_connection && @connected_since
379
+ Process.clock_gettime(Process::CLOCK_MONOTONIC) - @connected_since
380
+ end
381
+ end
382
+
383
+ # Mark the connection as needing to be retired, as if the age has
384
+ # exceeded the maximum allowed.
385
+ def force_retirement # :nodoc:
386
+ @connected_since &&= -Float::INFINITY
387
+ end
388
+
368
389
  def unprepared_statement
369
390
  cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements
370
391
  yield
@@ -579,8 +600,12 @@ module ActiveRecord
579
600
  false
580
601
  end
581
602
 
603
+ def supports_disabling_indexes?
604
+ false
605
+ end
606
+
582
607
  def return_value_after_insert?(column) # :nodoc:
583
- column.auto_incremented_by_db?
608
+ column.auto_populated?
584
609
  end
585
610
 
586
611
  def async_enabled? # :nodoc:
@@ -597,23 +622,31 @@ module ActiveRecord
597
622
  end
598
623
 
599
624
  # This is meant to be implemented by the adapters that support custom enum types
600
- def create_enum(*) # :nodoc:
625
+ def create_enum(...) # :nodoc:
601
626
  end
602
627
 
603
628
  # This is meant to be implemented by the adapters that support custom enum types
604
- def drop_enum(*) # :nodoc:
629
+ def drop_enum(...) # :nodoc:
605
630
  end
606
631
 
607
632
  # This is meant to be implemented by the adapters that support custom enum types
608
- def rename_enum(*) # :nodoc:
633
+ def rename_enum(...) # :nodoc:
609
634
  end
610
635
 
611
636
  # This is meant to be implemented by the adapters that support custom enum types
612
- def add_enum_value(*) # :nodoc:
637
+ def add_enum_value(...) # :nodoc:
613
638
  end
614
639
 
615
640
  # This is meant to be implemented by the adapters that support custom enum types
616
- def rename_enum_value(*) # :nodoc:
641
+ def rename_enum_value(...) # :nodoc:
642
+ end
643
+
644
+ # This is meant to be implemented by the adapters that support virtual tables
645
+ def create_virtual_table(*) # :nodoc:
646
+ end
647
+
648
+ # This is meant to be implemented by the adapters that support virtual tables
649
+ def drop_virtual_table(*) # :nodoc:
617
650
  end
618
651
 
619
652
  def advisory_locks_enabled? # :nodoc:
@@ -651,15 +684,6 @@ module ActiveRecord
651
684
  yield
652
685
  end
653
686
 
654
- # Override to check all foreign key constraints in a database.
655
- def all_foreign_keys_valid?
656
- check_all_foreign_keys_valid!
657
- true
658
- rescue ActiveRecord::StatementInvalid
659
- false
660
- end
661
- deprecate :all_foreign_keys_valid?, deprecator: ActiveRecord.deprecator
662
-
663
687
  # Override to check all foreign key constraints in a database.
664
688
  # The adapter should raise a +ActiveRecord::StatementInvalid+ if foreign key
665
689
  # constraints are not met.
@@ -668,6 +692,13 @@ module ActiveRecord
668
692
 
669
693
  # CONNECTION MANAGEMENT ====================================
670
694
 
695
+ # Checks whether the connection to the database was established. This doesn't
696
+ # include checking whether the database is actually capable of responding, i.e.
697
+ # whether the connection is stale.
698
+ def connected?
699
+ !@raw_connection.nil?
700
+ end
701
+
671
702
  # Checks whether the connection to the database is still active. This includes
672
703
  # checking whether the database is actually capable of responding, i.e. whether
673
704
  # the connection isn't stale.
@@ -682,32 +713,36 @@ module ActiveRecord
682
713
  deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline
683
714
 
684
715
  @lock.synchronize do
685
- reconnect
686
-
687
- enable_lazy_transactions!
688
- @raw_connection_dirty = false
689
- @verified = true
716
+ attempt_configure_connection do
717
+ @allow_preconnect = false
690
718
 
691
- reset_transaction(restore: restore_transactions) do
692
- clear_cache!(new_connection: true)
693
- configure_connection
694
- end
695
- rescue => original_exception
696
- translated_exception = translate_exception_class(original_exception, nil, nil)
697
- retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
719
+ reconnect
698
720
 
699
- if !retry_deadline_exceeded && retries_available > 0
700
- retries_available -= 1
721
+ enable_lazy_transactions!
722
+ @raw_connection_dirty = false
723
+ @last_activity = @connected_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
724
+ @verified = true
725
+ @allow_preconnect = true
701
726
 
702
- if retryable_connection_error?(translated_exception)
703
- backoff(connection_retries - retries_available)
704
- retry
727
+ reset_transaction(restore: restore_transactions) do
728
+ clear_cache!(new_connection: true)
729
+ configure_connection
705
730
  end
706
- end
731
+ rescue => original_exception
732
+ translated_exception = translate_exception_class(original_exception, nil, nil)
733
+ retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
707
734
 
708
- @verified = false
735
+ if !retry_deadline_exceeded && retries_available > 0
736
+ retries_available -= 1
709
737
 
710
- raise translated_exception
738
+ if retryable_connection_error?(translated_exception)
739
+ backoff(connection_retries - retries_available)
740
+ retry
741
+ end
742
+ end
743
+
744
+ raise translated_exception
745
+ end
711
746
  end
712
747
  end
713
748
 
@@ -718,6 +753,9 @@ module ActiveRecord
718
753
  clear_cache!(new_connection: true)
719
754
  reset_transaction
720
755
  @raw_connection_dirty = false
756
+ @connected_since = nil
757
+ @last_activity = nil
758
+ @verified = false
721
759
  end
722
760
  end
723
761
 
@@ -740,9 +778,11 @@ module ActiveRecord
740
778
  # should call super immediately after resetting the connection (and while
741
779
  # still holding @lock).
742
780
  def reset!
743
- clear_cache!(new_connection: true)
744
- reset_transaction
745
- configure_connection
781
+ attempt_configure_connection do
782
+ clear_cache!(new_connection: true)
783
+ reset_transaction
784
+ configure_connection
785
+ end
746
786
  end
747
787
 
748
788
  # Removes the connection from the pool and disconnect it.
@@ -776,10 +816,14 @@ module ActiveRecord
776
816
  unless active?
777
817
  @lock.synchronize do
778
818
  if @unconfigured_connection
779
- @raw_connection = @unconfigured_connection
780
- @unconfigured_connection = nil
781
- configure_connection
782
- @verified = true
819
+ attempt_configure_connection do
820
+ @raw_connection = @unconfigured_connection
821
+ @unconfigured_connection = nil
822
+ configure_connection
823
+ @last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
824
+ @verified = true
825
+ @allow_preconnect = true
826
+ end
783
827
  return
784
828
  end
785
829
 
@@ -787,6 +831,7 @@ module ActiveRecord
787
831
  end
788
832
  end
789
833
 
834
+ @last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
790
835
  @verified = true
791
836
  end
792
837
 
@@ -796,8 +841,15 @@ module ActiveRecord
796
841
  end
797
842
 
798
843
  def clean! # :nodoc:
799
- @raw_connection_dirty = false
800
- @verified = nil
844
+ _run_checkout_callbacks do
845
+ @raw_connection_dirty = false
846
+ @verified = nil
847
+ end
848
+ self
849
+ end
850
+
851
+ def verified? # :nodoc:
852
+ @verified
801
853
  end
802
854
 
803
855
  # Provides access to the underlying database driver for this adapter. For
@@ -867,7 +919,7 @@ module ActiveRecord
867
919
  end
868
920
 
869
921
  def database_version # :nodoc:
870
- schema_cache.database_version
922
+ pool.server_version(self)
871
923
  end
872
924
 
873
925
  def check_version # :nodoc:
@@ -878,14 +930,14 @@ module ActiveRecord
878
930
  # numbered migration that has been executed, or 0 if no schema
879
931
  # information is present / the database is empty.
880
932
  def schema_version
881
- migration_context.current_version
933
+ pool.migration_context.current_version
882
934
  end
883
935
 
884
936
  class << self
885
937
  def register_class_with_precision(mapping, key, klass, **kwargs) # :nodoc:
886
938
  mapping.register_type(key) do |*args|
887
939
  precision = extract_precision(args.last)
888
- klass.new(precision: precision, **kwargs)
940
+ klass.new(precision: precision, **kwargs).freeze
889
941
  end
890
942
  end
891
943
 
@@ -897,6 +949,10 @@ module ActiveRecord
897
949
  end
898
950
  end
899
951
 
952
+ def valid_type?(type) # :nodoc:
953
+ !native_database_types[type].nil?
954
+ end
955
+
900
956
  private
901
957
  def initialize_type_map(m)
902
958
  register_class_with_limit m, %r(boolean)i, Type::Boolean
@@ -916,7 +972,7 @@ module ActiveRecord
916
972
  m.alias_type %r(number)i, "decimal"
917
973
  m.alias_type %r(double)i, "float"
918
974
 
919
- m.register_type %r(^json)i, Type::Json.new
975
+ m.register_type %r(^json)i, Type::Json.new.freeze
920
976
 
921
977
  m.register_type(%r(decimal)i) do |sql_type|
922
978
  scale = extract_scale(sql_type)
@@ -924,9 +980,9 @@ module ActiveRecord
924
980
 
925
981
  if scale == 0
926
982
  # FIXME: Remove this class as well
927
- Type::DecimalWithoutScale.new(precision: precision)
983
+ Type::DecimalWithoutScale.new(precision: precision).freeze
928
984
  else
929
- Type::Decimal.new(precision: precision, scale: scale)
985
+ Type::Decimal.new(precision: precision, scale: scale).freeze
930
986
  end
931
987
  end
932
988
  end
@@ -934,7 +990,7 @@ module ActiveRecord
934
990
  def register_class_with_limit(mapping, key, klass)
935
991
  mapping.register_type(key) do |*args|
936
992
  limit = extract_limit(args.last)
937
- klass.new(limit: limit)
993
+ klass.new(limit: limit).freeze
938
994
  end
939
995
  end
940
996
 
@@ -1008,6 +1064,9 @@ module ActiveRecord
1008
1064
  if @verified
1009
1065
  # Cool, we're confident the connection's ready to use. (Note this might have
1010
1066
  # become true during the above #materialize_transactions.)
1067
+ elsif (last_activity = seconds_since_last_activity) && last_activity < verify_timeout
1068
+ # We haven't actually verified the connection since we acquired it, but it
1069
+ # has been used very recently. We're going to assume it's still okay.
1011
1070
  elsif reconnectable
1012
1071
  if allow_retry
1013
1072
  # Not sure about the connection yet, but if anything goes wrong we can
@@ -1049,6 +1108,7 @@ module ActiveRecord
1049
1108
  # Barring a known-retryable error inside the query (regardless of
1050
1109
  # whether we were in a _position_ to retry it), we should infer that
1051
1110
  # there's likely a real problem with the connection.
1111
+ @last_activity = nil
1052
1112
  @verified = false
1053
1113
  end
1054
1114
 
@@ -1063,11 +1123,13 @@ module ActiveRecord
1063
1123
  # `with_raw_connection` block only when the block is guaranteed to
1064
1124
  # exercise the raw connection.
1065
1125
  def verified!
1126
+ @last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
1066
1127
  @verified = true
1067
1128
  end
1068
1129
 
1069
1130
  def retryable_connection_error?(exception)
1070
- exception.is_a?(ConnectionNotEstablished) || exception.is_a?(ConnectionFailed)
1131
+ (exception.is_a?(ConnectionNotEstablished) && !exception.is_a?(ConnectionNotDefined)) ||
1132
+ exception.is_a?(ConnectionFailed)
1071
1133
  end
1072
1134
 
1073
1135
  def invalidate_transaction(exception)
@@ -1089,7 +1151,7 @@ module ActiveRecord
1089
1151
  end
1090
1152
 
1091
1153
  def reconnect
1092
- raise NotImplementedError
1154
+ raise NotImplementedError.new("#{self.class} should define `reconnect` to implement adapter-specific logic for reconnecting to the database")
1093
1155
  end
1094
1156
 
1095
1157
  # Returns a raw connection for internal use with methods that are known
@@ -1128,37 +1190,39 @@ module ActiveRecord
1128
1190
  end
1129
1191
  end
1130
1192
 
1131
- def translate_exception_class(e, sql, binds)
1132
- message = "#{e.class.name}: #{e.message}"
1193
+ def translate_exception_class(native_error, sql, binds)
1194
+ return native_error if native_error.is_a?(ActiveRecordError)
1133
1195
 
1134
- exception = translate_exception(
1135
- e, message: message, sql: sql, binds: binds
1196
+ message = "#{native_error.class.name}: #{native_error.message}"
1197
+
1198
+ active_record_error = translate_exception(
1199
+ native_error, message: message, sql: sql, binds: binds
1136
1200
  )
1137
- exception.set_backtrace e.backtrace
1138
- exception
1201
+ active_record_error.set_backtrace(native_error.backtrace)
1202
+ active_record_error
1139
1203
  end
1140
1204
 
1141
- def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false, &block) # :doc:
1142
- @instrumenter.instrument(
1205
+ def log(sql, name = "SQL", binds = [], type_casted_binds = [], async: false, allow_retry: false, &block) # :doc:
1206
+ instrumenter.instrument(
1143
1207
  "sql.active_record",
1144
1208
  sql: sql,
1145
1209
  name: name,
1146
1210
  binds: binds,
1147
1211
  type_casted_binds: type_casted_binds,
1148
- statement_name: statement_name,
1149
1212
  async: async,
1213
+ allow_retry: allow_retry,
1150
1214
  connection: self,
1215
+ transaction: current_transaction.user_transaction.presence,
1216
+ affected_rows: 0,
1217
+ row_count: 0,
1151
1218
  &block
1152
1219
  )
1153
1220
  rescue ActiveRecord::StatementInvalid => ex
1154
1221
  raise ex.set_query(sql, binds)
1155
1222
  end
1156
1223
 
1157
- def transform_query(sql)
1158
- ActiveRecord.query_transformers.each do |transformer|
1159
- sql = transformer.call(sql, self)
1160
- end
1161
- sql
1224
+ def instrumenter # :nodoc:
1225
+ ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] ||= ActiveSupport::Notifications.instrumenter
1162
1226
  end
1163
1227
 
1164
1228
  def translate_exception(exception, message:, sql:, binds:)
@@ -1171,10 +1235,6 @@ module ActiveRecord
1171
1235
  end
1172
1236
  end
1173
1237
 
1174
- def without_prepared_statement?(binds)
1175
- !prepared_statements || binds.empty?
1176
- end
1177
-
1178
1238
  def column_for(table_name, column_name)
1179
1239
  column_name = column_name.to_s
1180
1240
  columns(table_name).detect { |c| c.name == column_name } ||
@@ -1211,7 +1271,7 @@ module ActiveRecord
1211
1271
  #
1212
1272
  # This is an internal hook to make possible connection adapters to build
1213
1273
  # custom result objects with connection-specific data.
1214
- def build_result(columns:, rows:, column_types: {})
1274
+ def build_result(columns:, rows:, column_types: nil)
1215
1275
  ActiveRecord::Result.new(columns, rows, column_types)
1216
1276
  end
1217
1277
 
@@ -1223,6 +1283,14 @@ module ActiveRecord
1223
1283
  # Implementations may assume this method will only be called while
1224
1284
  # holding @lock (or from #initialize).
1225
1285
  def configure_connection
1286
+ check_version
1287
+ end
1288
+
1289
+ def attempt_configure_connection
1290
+ yield
1291
+ rescue Exception # Need to handle things such as Timeout::ExitException
1292
+ disconnect!
1293
+ raise
1226
1294
  end
1227
1295
 
1228
1296
  def default_prepared_statements