activerecord 7.2.2.1 → 8.1.2

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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +564 -753
  3. data/README.rdoc +2 -2
  4. data/lib/active_record/association_relation.rb +2 -1
  5. data/lib/active_record/associations/alias_tracker.rb +6 -4
  6. data/lib/active_record/associations/association.rb +35 -11
  7. data/lib/active_record/associations/belongs_to_association.rb +18 -2
  8. data/lib/active_record/associations/builder/association.rb +23 -11
  9. data/lib/active_record/associations/builder/belongs_to.rb +17 -4
  10. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  11. data/lib/active_record/associations/builder/has_one.rb +1 -1
  12. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  13. data/lib/active_record/associations/collection_association.rb +10 -8
  14. data/lib/active_record/associations/collection_proxy.rb +22 -4
  15. data/lib/active_record/associations/deprecation.rb +88 -0
  16. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  17. data/lib/active_record/associations/errors.rb +3 -0
  18. data/lib/active_record/associations/has_many_through_association.rb +3 -2
  19. data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
  20. data/lib/active_record/associations/join_dependency.rb +4 -2
  21. data/lib/active_record/associations/preloader/association.rb +2 -2
  22. data/lib/active_record/associations/preloader/batch.rb +7 -1
  23. data/lib/active_record/associations/preloader/branch.rb +1 -0
  24. data/lib/active_record/associations/singular_association.rb +8 -3
  25. data/lib/active_record/associations.rb +192 -24
  26. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  27. data/lib/active_record/attribute_methods/primary_key.rb +4 -8
  28. data/lib/active_record/attribute_methods/query.rb +34 -0
  29. data/lib/active_record/attribute_methods/serialization.rb +17 -4
  30. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
  31. data/lib/active_record/attribute_methods.rb +24 -19
  32. data/lib/active_record/attributes.rb +40 -26
  33. data/lib/active_record/autosave_association.rb +91 -39
  34. data/lib/active_record/base.rb +3 -4
  35. data/lib/active_record/coders/json.rb +14 -5
  36. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
  37. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
  38. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -13
  39. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +458 -117
  40. data/lib/active_record/connection_adapters/abstract/database_statements.rb +136 -74
  41. data/lib/active_record/connection_adapters/abstract/query_cache.rb +44 -11
  42. data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
  43. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
  44. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
  45. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  46. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -29
  47. data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
  48. data/lib/active_record/connection_adapters/abstract_adapter.rb +175 -87
  49. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +77 -58
  50. data/lib/active_record/connection_adapters/column.rb +17 -4
  51. data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
  52. data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
  53. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  54. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
  55. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +73 -46
  56. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
  57. data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -11
  58. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  59. data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
  60. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
  61. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
  62. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  63. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  64. data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
  65. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  66. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
  67. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +28 -45
  68. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
  69. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +140 -64
  70. data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -105
  71. data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
  72. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
  73. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
  74. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  75. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
  76. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +13 -13
  77. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +112 -42
  78. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  79. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
  80. data/lib/active_record/connection_adapters/trilogy_adapter.rb +2 -19
  81. data/lib/active_record/connection_adapters.rb +1 -56
  82. data/lib/active_record/connection_handling.rb +37 -10
  83. data/lib/active_record/core.rb +61 -25
  84. data/lib/active_record/counter_cache.rb +34 -9
  85. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
  86. data/lib/active_record/database_configurations/database_config.rb +9 -1
  87. data/lib/active_record/database_configurations/hash_config.rb +67 -9
  88. data/lib/active_record/database_configurations/url_config.rb +13 -3
  89. data/lib/active_record/database_configurations.rb +7 -3
  90. data/lib/active_record/delegated_type.rb +19 -19
  91. data/lib/active_record/dynamic_matchers.rb +54 -69
  92. data/lib/active_record/encryption/config.rb +3 -1
  93. data/lib/active_record/encryption/encryptable_record.rb +9 -9
  94. data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
  95. data/lib/active_record/encryption/encryptor.rb +49 -28
  96. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  97. data/lib/active_record/encryption/scheme.rb +9 -2
  98. data/lib/active_record/enum.rb +46 -42
  99. data/lib/active_record/errors.rb +36 -12
  100. data/lib/active_record/explain.rb +1 -1
  101. data/lib/active_record/explain_registry.rb +51 -2
  102. data/lib/active_record/filter_attribute_handler.rb +73 -0
  103. data/lib/active_record/fixture_set/table_row.rb +19 -2
  104. data/lib/active_record/fixtures.rb +2 -4
  105. data/lib/active_record/future_result.rb +13 -9
  106. data/lib/active_record/gem_version.rb +3 -3
  107. data/lib/active_record/inheritance.rb +1 -1
  108. data/lib/active_record/insert_all.rb +12 -7
  109. data/lib/active_record/locking/optimistic.rb +8 -1
  110. data/lib/active_record/locking/pessimistic.rb +5 -0
  111. data/lib/active_record/log_subscriber.rb +3 -13
  112. data/lib/active_record/middleware/shard_selector.rb +34 -17
  113. data/lib/active_record/migration/command_recorder.rb +44 -11
  114. data/lib/active_record/migration/compatibility.rb +37 -24
  115. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  116. data/lib/active_record/migration.rb +50 -43
  117. data/lib/active_record/model_schema.rb +38 -13
  118. data/lib/active_record/nested_attributes.rb +6 -6
  119. data/lib/active_record/persistence.rb +162 -133
  120. data/lib/active_record/query_cache.rb +22 -15
  121. data/lib/active_record/query_logs.rb +104 -52
  122. data/lib/active_record/query_logs_formatter.rb +17 -28
  123. data/lib/active_record/querying.rb +12 -12
  124. data/lib/active_record/railtie.rb +37 -32
  125. data/lib/active_record/railties/controller_runtime.rb +11 -6
  126. data/lib/active_record/railties/databases.rake +26 -37
  127. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  128. data/lib/active_record/railties/job_runtime.rb +10 -11
  129. data/lib/active_record/reflection.rb +53 -21
  130. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  131. data/lib/active_record/relation/batches.rb +147 -73
  132. data/lib/active_record/relation/calculations.rb +80 -63
  133. data/lib/active_record/relation/delegation.rb +25 -15
  134. data/lib/active_record/relation/finder_methods.rb +54 -37
  135. data/lib/active_record/relation/merger.rb +8 -8
  136. data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
  137. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
  138. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  139. data/lib/active_record/relation/predicate_builder.rb +22 -7
  140. data/lib/active_record/relation/query_attribute.rb +4 -2
  141. data/lib/active_record/relation/query_methods.rb +156 -95
  142. data/lib/active_record/relation/spawn_methods.rb +7 -7
  143. data/lib/active_record/relation/where_clause.rb +10 -11
  144. data/lib/active_record/relation.rb +122 -80
  145. data/lib/active_record/result.rb +109 -24
  146. data/lib/active_record/runtime_registry.rb +42 -58
  147. data/lib/active_record/sanitization.rb +9 -6
  148. data/lib/active_record/schema_dumper.rb +47 -22
  149. data/lib/active_record/schema_migration.rb +2 -1
  150. data/lib/active_record/scoping/named.rb +5 -2
  151. data/lib/active_record/scoping.rb +0 -1
  152. data/lib/active_record/secure_token.rb +3 -3
  153. data/lib/active_record/signed_id.rb +47 -18
  154. data/lib/active_record/statement_cache.rb +24 -20
  155. data/lib/active_record/store.rb +51 -22
  156. data/lib/active_record/structured_event_subscriber.rb +85 -0
  157. data/lib/active_record/table_metadata.rb +6 -23
  158. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  159. data/lib/active_record/tasks/database_tasks.rb +85 -85
  160. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
  161. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
  162. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
  163. data/lib/active_record/test_databases.rb +14 -4
  164. data/lib/active_record/test_fixtures.rb +39 -2
  165. data/lib/active_record/testing/query_assertions.rb +8 -2
  166. data/lib/active_record/timestamp.rb +4 -2
  167. data/lib/active_record/token_for.rb +1 -1
  168. data/lib/active_record/transaction.rb +2 -5
  169. data/lib/active_record/transactions.rb +39 -16
  170. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  171. data/lib/active_record/type/internal/timezone.rb +7 -0
  172. data/lib/active_record/type/json.rb +15 -2
  173. data/lib/active_record/type/serialized.rb +11 -4
  174. data/lib/active_record/type/type_map.rb +1 -1
  175. data/lib/active_record/type_caster/connection.rb +2 -1
  176. data/lib/active_record/validations/associated.rb +1 -1
  177. data/lib/active_record/validations/uniqueness.rb +8 -8
  178. data/lib/active_record.rb +85 -50
  179. data/lib/arel/alias_predication.rb +2 -0
  180. data/lib/arel/collectors/bind.rb +2 -2
  181. data/lib/arel/collectors/sql_string.rb +1 -1
  182. data/lib/arel/collectors/substitute_binds.rb +2 -2
  183. data/lib/arel/crud.rb +8 -11
  184. data/lib/arel/delete_manager.rb +5 -0
  185. data/lib/arel/nodes/binary.rb +1 -1
  186. data/lib/arel/nodes/count.rb +2 -2
  187. data/lib/arel/nodes/delete_statement.rb +4 -2
  188. data/lib/arel/nodes/function.rb +4 -10
  189. data/lib/arel/nodes/named_function.rb +2 -2
  190. data/lib/arel/nodes/node.rb +2 -2
  191. data/lib/arel/nodes/sql_literal.rb +1 -1
  192. data/lib/arel/nodes/update_statement.rb +4 -2
  193. data/lib/arel/nodes.rb +0 -2
  194. data/lib/arel/select_manager.rb +13 -4
  195. data/lib/arel/table.rb +3 -7
  196. data/lib/arel/update_manager.rb +5 -0
  197. data/lib/arel/visitors/dot.rb +2 -3
  198. data/lib/arel/visitors/postgresql.rb +55 -0
  199. data/lib/arel/visitors/sqlite.rb +55 -8
  200. data/lib/arel/visitors/to_sql.rb +6 -22
  201. data/lib/arel.rb +3 -1
  202. data/lib/rails/generators/active_record/application_record/USAGE +1 -1
  203. metadata +17 -17
  204. data/lib/active_record/explain_subscriber.rb +0 -34
  205. data/lib/active_record/normalization.rb +0 -163
  206. data/lib/active_record/relation/record_fetch_warning.rb +0 -52
@@ -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"
@@ -43,6 +43,8 @@ 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)
@@ -51,7 +53,11 @@ module ActiveRecord
51
53
  @pool = value
52
54
  end
53
55
 
54
- 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
55
61
 
56
62
  def self.type_cast_config_to_integer(config)
57
63
  if config.is_a?(Integer)
@@ -120,7 +126,7 @@ module ActiveRecord
120
126
 
121
127
  # Opens a database console session.
122
128
  def self.dbconsole(config, options = {})
123
- 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")
124
130
  end
125
131
 
126
132
  def initialize(config_or_deprecated_connection, deprecated_logger = nil, deprecated_connection_options = nil, deprecated_config = nil) # :nodoc:
@@ -128,6 +134,7 @@ module ActiveRecord
128
134
 
129
135
  @raw_connection = nil
130
136
  @unconfigured_connection = nil
137
+ @connected_since = nil
131
138
 
132
139
  if config_or_deprecated_connection.is_a?(Hash)
133
140
  @config = config_or_deprecated_connection.symbolize_keys
@@ -140,6 +147,7 @@ module ActiveRecord
140
147
  # Soft-deprecated for now; we'll probably warn in future.
141
148
 
142
149
  @unconfigured_connection = config_or_deprecated_connection
150
+ @connected_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
143
151
  @logger = deprecated_logger || ActiveRecord::Base.logger
144
152
  if deprecated_config
145
153
  @config = (deprecated_config || {}).symbolize_keys
@@ -151,9 +159,10 @@ module ActiveRecord
151
159
  end
152
160
 
153
161
  @owner = nil
154
- @instrumenter = ActiveSupport::Notifications.instrumenter
162
+ @pinned = false
155
163
  @pool = ActiveRecord::ConnectionAdapters::NullPool.new
156
164
  @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
165
+ @allow_preconnect = false
157
166
  @visitor = arel_visitor
158
167
  @statements = build_statement_pool
159
168
  self.lock_thread = nil
@@ -169,7 +178,10 @@ module ActiveRecord
169
178
  @default_timezone = self.class.validate_default_timezone(@config[:default_timezone])
170
179
 
171
180
  @raw_connection_dirty = false
181
+ @last_activity = nil
172
182
  @verified = false
183
+
184
+ @pool_jitter = rand * max_jitter
173
185
  end
174
186
 
175
187
  def inspect # :nodoc:
@@ -183,31 +195,23 @@ module ActiveRecord
183
195
  @lock =
184
196
  case lock_thread
185
197
  when Thread
186
- ActiveSupport::Concurrency::ThreadLoadInterlockAwareMonitor.new
198
+ ActiveSupport::Concurrency::ThreadMonitor.new
187
199
  when Fiber
188
- ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
200
+ ::Monitor.new
189
201
  else
190
202
  ActiveSupport::Concurrency::NullLock
191
203
  end
192
204
  end
193
205
 
194
- EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
195
- EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze # :nodoc:
196
- private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
197
- def with_instrumenter(instrumenter, &block) # :nodoc:
198
- Thread.handle_interrupt(EXCEPTION_NEVER) do
199
- previous_instrumenter = @instrumenter
200
- @instrumenter = instrumenter
201
- Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
202
- ensure
203
- @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}"
204
209
  end
205
210
  end
206
211
 
207
- def check_if_write_query(sql) # :nodoc:
208
- if preventing_writes? && write_query?(sql)
209
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
210
- end
212
+ MAX_JITTER = 0.0..1.0 # :nodoc:
213
+ def max_jitter
214
+ (@config[:pool_jitter] || 0.2).to_f.clamp(MAX_JITTER)
211
215
  end
212
216
 
213
217
  def replica?
@@ -218,6 +222,10 @@ module ActiveRecord
218
222
  (@config[:connection_retries] || 1).to_i
219
223
  end
220
224
 
225
+ def verify_timeout
226
+ (@config[:verify_timeout] || 2).to_i
227
+ end
228
+
221
229
  def retry_deadline
222
230
  if @config[:retry_deadline]
223
231
  @config[:retry_deadline].to_f
@@ -236,9 +244,9 @@ module ActiveRecord
236
244
  # the value of +current_preventing_writes+.
237
245
  def preventing_writes?
238
246
  return true if replica?
239
- return false if connection_class.nil?
247
+ return false if connection_descriptor.nil?
240
248
 
241
- connection_class.current_preventing_writes
249
+ connection_descriptor.current_preventing_writes
242
250
  end
243
251
 
244
252
  def prepared_statements?
@@ -270,7 +278,11 @@ module ActiveRecord
270
278
  end
271
279
 
272
280
  def valid_type?(type) # :nodoc:
273
- !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
274
286
  end
275
287
 
276
288
  # this method must only be called while holding connection pool's mutex
@@ -289,8 +301,8 @@ module ActiveRecord
289
301
  @owner = ActiveSupport::IsolatedExecutionState.context
290
302
  end
291
303
 
292
- def connection_class # :nodoc:
293
- @pool.connection_class
304
+ def connection_descriptor # :nodoc:
305
+ @pool.connection_descriptor
294
306
  end
295
307
 
296
308
  # The role (e.g. +:writing+) for the current connection. In a
@@ -309,8 +321,12 @@ module ActiveRecord
309
321
  @pool.schema_cache || (@schema_cache ||= BoundSchemaReflection.for_lone_connection(@pool.schema_reflection, self))
310
322
  end
311
323
 
324
+ def pool_jitter(duration)
325
+ duration * (1.0 - @pool_jitter)
326
+ end
327
+
312
328
  # this method must only be called while holding connection pool's mutex
313
- def expire
329
+ def expire(update_idle = true) # :nodoc:
314
330
  if in_use?
315
331
  if @owner != ActiveSupport::IsolatedExecutionState.context
316
332
  raise ActiveRecordError, "Cannot expire connection, " \
@@ -318,8 +334,12 @@ module ActiveRecord
318
334
  "Current thread: #{ActiveSupport::IsolatedExecutionState.context}."
319
335
  end
320
336
 
321
- @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
322
- @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
323
343
  else
324
344
  raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
325
345
  end
@@ -344,6 +364,28 @@ module ActiveRecord
344
364
  Process.clock_gettime(Process::CLOCK_MONOTONIC) - @idle_since
345
365
  end
346
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
+
347
389
  def unprepared_statement
348
390
  cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements
349
391
  yield
@@ -558,6 +600,10 @@ module ActiveRecord
558
600
  false
559
601
  end
560
602
 
603
+ def supports_disabling_indexes?
604
+ false
605
+ end
606
+
561
607
  def return_value_after_insert?(column) # :nodoc:
562
608
  column.auto_populated?
563
609
  end
@@ -576,23 +622,31 @@ module ActiveRecord
576
622
  end
577
623
 
578
624
  # This is meant to be implemented by the adapters that support custom enum types
579
- def create_enum(*) # :nodoc:
625
+ def create_enum(...) # :nodoc:
580
626
  end
581
627
 
582
628
  # This is meant to be implemented by the adapters that support custom enum types
583
- def drop_enum(*) # :nodoc:
629
+ def drop_enum(...) # :nodoc:
584
630
  end
585
631
 
586
632
  # This is meant to be implemented by the adapters that support custom enum types
587
- def rename_enum(*) # :nodoc:
633
+ def rename_enum(...) # :nodoc:
588
634
  end
589
635
 
590
636
  # This is meant to be implemented by the adapters that support custom enum types
591
- def add_enum_value(*) # :nodoc:
637
+ def add_enum_value(...) # :nodoc:
592
638
  end
593
639
 
594
640
  # This is meant to be implemented by the adapters that support custom enum types
595
- 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:
596
650
  end
597
651
 
598
652
  def advisory_locks_enabled? # :nodoc:
@@ -659,32 +713,36 @@ module ActiveRecord
659
713
  deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline
660
714
 
661
715
  @lock.synchronize do
662
- reconnect
663
-
664
- enable_lazy_transactions!
665
- @raw_connection_dirty = false
666
- @verified = true
716
+ attempt_configure_connection do
717
+ @allow_preconnect = false
667
718
 
668
- reset_transaction(restore: restore_transactions) do
669
- clear_cache!(new_connection: true)
670
- configure_connection
671
- end
672
- rescue => original_exception
673
- translated_exception = translate_exception_class(original_exception, nil, nil)
674
- retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
719
+ reconnect
675
720
 
676
- if !retry_deadline_exceeded && retries_available > 0
677
- 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
678
726
 
679
- if retryable_connection_error?(translated_exception)
680
- backoff(connection_retries - retries_available)
681
- retry
727
+ reset_transaction(restore: restore_transactions) do
728
+ clear_cache!(new_connection: true)
729
+ configure_connection
682
730
  end
683
- 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)
684
734
 
685
- @verified = false
735
+ if !retry_deadline_exceeded && retries_available > 0
736
+ retries_available -= 1
686
737
 
687
- 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
688
746
  end
689
747
  end
690
748
 
@@ -695,6 +753,9 @@ module ActiveRecord
695
753
  clear_cache!(new_connection: true)
696
754
  reset_transaction
697
755
  @raw_connection_dirty = false
756
+ @connected_since = nil
757
+ @last_activity = nil
758
+ @verified = false
698
759
  end
699
760
  end
700
761
 
@@ -717,9 +778,11 @@ module ActiveRecord
717
778
  # should call super immediately after resetting the connection (and while
718
779
  # still holding @lock).
719
780
  def reset!
720
- clear_cache!(new_connection: true)
721
- reset_transaction
722
- configure_connection
781
+ attempt_configure_connection do
782
+ clear_cache!(new_connection: true)
783
+ reset_transaction
784
+ configure_connection
785
+ end
723
786
  end
724
787
 
725
788
  # Removes the connection from the pool and disconnect it.
@@ -753,10 +816,14 @@ module ActiveRecord
753
816
  unless active?
754
817
  @lock.synchronize do
755
818
  if @unconfigured_connection
756
- @raw_connection = @unconfigured_connection
757
- @unconfigured_connection = nil
758
- configure_connection
759
- @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
760
827
  return
761
828
  end
762
829
 
@@ -764,6 +831,7 @@ module ActiveRecord
764
831
  end
765
832
  end
766
833
 
834
+ @last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
767
835
  @verified = true
768
836
  end
769
837
 
@@ -773,8 +841,15 @@ module ActiveRecord
773
841
  end
774
842
 
775
843
  def clean! # :nodoc:
776
- @raw_connection_dirty = false
777
- @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
778
853
  end
779
854
 
780
855
  # Provides access to the underlying database driver for this adapter. For
@@ -862,7 +937,7 @@ module ActiveRecord
862
937
  def register_class_with_precision(mapping, key, klass, **kwargs) # :nodoc:
863
938
  mapping.register_type(key) do |*args|
864
939
  precision = extract_precision(args.last)
865
- klass.new(precision: precision, **kwargs)
940
+ klass.new(precision: precision, **kwargs).freeze
866
941
  end
867
942
  end
868
943
 
@@ -874,6 +949,10 @@ module ActiveRecord
874
949
  end
875
950
  end
876
951
 
952
+ def valid_type?(type) # :nodoc:
953
+ !native_database_types[type].nil?
954
+ end
955
+
877
956
  private
878
957
  def initialize_type_map(m)
879
958
  register_class_with_limit m, %r(boolean)i, Type::Boolean
@@ -893,7 +972,7 @@ module ActiveRecord
893
972
  m.alias_type %r(number)i, "decimal"
894
973
  m.alias_type %r(double)i, "float"
895
974
 
896
- m.register_type %r(^json)i, Type::Json.new
975
+ m.register_type %r(^json)i, Type::Json.new.freeze
897
976
 
898
977
  m.register_type(%r(decimal)i) do |sql_type|
899
978
  scale = extract_scale(sql_type)
@@ -901,9 +980,9 @@ module ActiveRecord
901
980
 
902
981
  if scale == 0
903
982
  # FIXME: Remove this class as well
904
- Type::DecimalWithoutScale.new(precision: precision)
983
+ Type::DecimalWithoutScale.new(precision: precision).freeze
905
984
  else
906
- Type::Decimal.new(precision: precision, scale: scale)
985
+ Type::Decimal.new(precision: precision, scale: scale).freeze
907
986
  end
908
987
  end
909
988
  end
@@ -911,7 +990,7 @@ module ActiveRecord
911
990
  def register_class_with_limit(mapping, key, klass)
912
991
  mapping.register_type(key) do |*args|
913
992
  limit = extract_limit(args.last)
914
- klass.new(limit: limit)
993
+ klass.new(limit: limit).freeze
915
994
  end
916
995
  end
917
996
 
@@ -985,6 +1064,9 @@ module ActiveRecord
985
1064
  if @verified
986
1065
  # Cool, we're confident the connection's ready to use. (Note this might have
987
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.
988
1070
  elsif reconnectable
989
1071
  if allow_retry
990
1072
  # Not sure about the connection yet, but if anything goes wrong we can
@@ -1026,6 +1108,7 @@ module ActiveRecord
1026
1108
  # Barring a known-retryable error inside the query (regardless of
1027
1109
  # whether we were in a _position_ to retry it), we should infer that
1028
1110
  # there's likely a real problem with the connection.
1111
+ @last_activity = nil
1029
1112
  @verified = false
1030
1113
  end
1031
1114
 
@@ -1040,11 +1123,13 @@ module ActiveRecord
1040
1123
  # `with_raw_connection` block only when the block is guaranteed to
1041
1124
  # exercise the raw connection.
1042
1125
  def verified!
1126
+ @last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
1043
1127
  @verified = true
1044
1128
  end
1045
1129
 
1046
1130
  def retryable_connection_error?(exception)
1047
- exception.is_a?(ConnectionNotEstablished) || exception.is_a?(ConnectionFailed)
1131
+ (exception.is_a?(ConnectionNotEstablished) && !exception.is_a?(ConnectionNotDefined)) ||
1132
+ exception.is_a?(ConnectionFailed)
1048
1133
  end
1049
1134
 
1050
1135
  def invalidate_transaction(exception)
@@ -1066,7 +1151,7 @@ module ActiveRecord
1066
1151
  end
1067
1152
 
1068
1153
  def reconnect
1069
- raise NotImplementedError
1154
+ raise NotImplementedError.new("#{self.class} should define `reconnect` to implement adapter-specific logic for reconnecting to the database")
1070
1155
  end
1071
1156
 
1072
1157
  # Returns a raw connection for internal use with methods that are known
@@ -1105,27 +1190,30 @@ module ActiveRecord
1105
1190
  end
1106
1191
  end
1107
1192
 
1108
- def translate_exception_class(e, sql, binds)
1109
- 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)
1195
+
1196
+ message = "#{native_error.class.name}: #{native_error.message}"
1110
1197
 
1111
- exception = translate_exception(
1112
- e, message: message, sql: sql, binds: binds
1198
+ active_record_error = translate_exception(
1199
+ native_error, message: message, sql: sql, binds: binds
1113
1200
  )
1114
- exception.set_backtrace e.backtrace
1115
- exception
1201
+ active_record_error.set_backtrace(native_error.backtrace)
1202
+ active_record_error
1116
1203
  end
1117
1204
 
1118
- def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false, &block) # :doc:
1119
- @instrumenter.instrument(
1205
+ def log(sql, name = "SQL", binds = [], type_casted_binds = [], async: false, allow_retry: false, &block) # :doc:
1206
+ instrumenter.instrument(
1120
1207
  "sql.active_record",
1121
1208
  sql: sql,
1122
1209
  name: name,
1123
1210
  binds: binds,
1124
1211
  type_casted_binds: type_casted_binds,
1125
- statement_name: statement_name,
1126
1212
  async: async,
1213
+ allow_retry: allow_retry,
1127
1214
  connection: self,
1128
1215
  transaction: current_transaction.user_transaction.presence,
1216
+ affected_rows: 0,
1129
1217
  row_count: 0,
1130
1218
  &block
1131
1219
  )
@@ -1133,11 +1221,8 @@ module ActiveRecord
1133
1221
  raise ex.set_query(sql, binds)
1134
1222
  end
1135
1223
 
1136
- def transform_query(sql)
1137
- ActiveRecord.query_transformers.each do |transformer|
1138
- sql = transformer.call(sql, self)
1139
- end
1140
- sql
1224
+ def instrumenter # :nodoc:
1225
+ ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] ||= ActiveSupport::Notifications.instrumenter
1141
1226
  end
1142
1227
 
1143
1228
  def translate_exception(exception, message:, sql:, binds:)
@@ -1150,10 +1235,6 @@ module ActiveRecord
1150
1235
  end
1151
1236
  end
1152
1237
 
1153
- def without_prepared_statement?(binds)
1154
- !prepared_statements || binds.empty?
1155
- end
1156
-
1157
1238
  def column_for(table_name, column_name)
1158
1239
  column_name = column_name.to_s
1159
1240
  columns(table_name).detect { |c| c.name == column_name } ||
@@ -1205,6 +1286,13 @@ module ActiveRecord
1205
1286
  check_version
1206
1287
  end
1207
1288
 
1289
+ def attempt_configure_connection
1290
+ yield
1291
+ rescue Exception # Need to handle things such as Timeout::ExitException
1292
+ disconnect!
1293
+ raise
1294
+ end
1295
+
1208
1296
  def default_prepared_statements
1209
1297
  true
1210
1298
  end