activerecord 7.2.3 → 8.1.3

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 (198) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +612 -1055
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/association_relation.rb +2 -1
  5. data/lib/active_record/associations/association.rb +35 -11
  6. data/lib/active_record/associations/builder/association.rb +23 -11
  7. data/lib/active_record/associations/builder/belongs_to.rb +17 -4
  8. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  9. data/lib/active_record/associations/builder/has_one.rb +1 -1
  10. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  11. data/lib/active_record/associations/collection_association.rb +1 -1
  12. data/lib/active_record/associations/collection_proxy.rb +22 -4
  13. data/lib/active_record/associations/deprecation.rb +88 -0
  14. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  15. data/lib/active_record/associations/errors.rb +3 -0
  16. data/lib/active_record/associations/has_many_through_association.rb +3 -2
  17. data/lib/active_record/associations/join_dependency.rb +4 -2
  18. data/lib/active_record/associations/preloader/association.rb +2 -2
  19. data/lib/active_record/associations/preloader/batch.rb +7 -1
  20. data/lib/active_record/associations/preloader/branch.rb +1 -0
  21. data/lib/active_record/associations/singular_association.rb +8 -3
  22. data/lib/active_record/associations.rb +192 -24
  23. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  24. data/lib/active_record/attribute_methods/primary_key.rb +4 -8
  25. data/lib/active_record/attribute_methods/query.rb +34 -0
  26. data/lib/active_record/attribute_methods/serialization.rb +16 -3
  27. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
  28. data/lib/active_record/attributes.rb +3 -0
  29. data/lib/active_record/autosave_association.rb +69 -27
  30. data/lib/active_record/base.rb +1 -2
  31. data/lib/active_record/coders/json.rb +14 -5
  32. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
  33. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
  34. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -13
  35. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +412 -88
  36. data/lib/active_record/connection_adapters/abstract/database_statements.rb +137 -75
  37. data/lib/active_record/connection_adapters/abstract/query_cache.rb +27 -5
  38. data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
  39. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
  40. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +32 -35
  41. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  42. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -32
  43. data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
  44. data/lib/active_record/connection_adapters/abstract_adapter.rb +150 -91
  45. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +63 -52
  46. data/lib/active_record/connection_adapters/column.rb +17 -4
  47. data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
  48. data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
  49. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  50. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
  51. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +73 -46
  52. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
  53. data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -10
  54. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  55. data/lib/active_record/connection_adapters/postgresql/column.rb +8 -2
  56. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
  57. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
  58. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  59. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  60. data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
  61. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  62. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
  63. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +14 -33
  64. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +71 -32
  65. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +139 -63
  66. data/lib/active_record/connection_adapters/postgresql_adapter.rb +78 -105
  67. data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
  68. data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
  69. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
  70. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -8
  71. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  72. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
  73. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +13 -14
  74. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +102 -37
  75. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  76. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
  77. data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -18
  78. data/lib/active_record/connection_adapters.rb +1 -56
  79. data/lib/active_record/connection_handling.rb +25 -2
  80. data/lib/active_record/core.rb +33 -17
  81. data/lib/active_record/counter_cache.rb +33 -8
  82. data/lib/active_record/database_configurations/database_config.rb +9 -1
  83. data/lib/active_record/database_configurations/hash_config.rb +67 -9
  84. data/lib/active_record/database_configurations/url_config.rb +13 -3
  85. data/lib/active_record/database_configurations.rb +7 -3
  86. data/lib/active_record/delegated_type.rb +1 -1
  87. data/lib/active_record/dynamic_matchers.rb +54 -69
  88. data/lib/active_record/encryption/config.rb +3 -1
  89. data/lib/active_record/encryption/encryptable_record.rb +8 -8
  90. data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
  91. data/lib/active_record/encryption/encryptor.rb +28 -8
  92. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  93. data/lib/active_record/encryption/scheme.rb +9 -2
  94. data/lib/active_record/enum.rb +33 -30
  95. data/lib/active_record/errors.rb +33 -9
  96. data/lib/active_record/explain.rb +1 -1
  97. data/lib/active_record/explain_registry.rb +51 -2
  98. data/lib/active_record/filter_attribute_handler.rb +73 -0
  99. data/lib/active_record/fixtures.rb +2 -4
  100. data/lib/active_record/future_result.rb +15 -9
  101. data/lib/active_record/gem_version.rb +2 -2
  102. data/lib/active_record/inheritance.rb +1 -1
  103. data/lib/active_record/insert_all.rb +14 -9
  104. data/lib/active_record/locking/optimistic.rb +8 -1
  105. data/lib/active_record/locking/pessimistic.rb +5 -0
  106. data/lib/active_record/log_subscriber.rb +3 -13
  107. data/lib/active_record/middleware/shard_selector.rb +34 -17
  108. data/lib/active_record/migration/command_recorder.rb +45 -12
  109. data/lib/active_record/migration/compatibility.rb +37 -24
  110. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  111. data/lib/active_record/migration.rb +48 -42
  112. data/lib/active_record/model_schema.rb +38 -13
  113. data/lib/active_record/nested_attributes.rb +6 -6
  114. data/lib/active_record/persistence.rb +162 -133
  115. data/lib/active_record/query_cache.rb +22 -15
  116. data/lib/active_record/query_logs.rb +100 -52
  117. data/lib/active_record/query_logs_formatter.rb +17 -28
  118. data/lib/active_record/querying.rb +8 -8
  119. data/lib/active_record/railtie.rb +35 -30
  120. data/lib/active_record/railties/controller_runtime.rb +11 -6
  121. data/lib/active_record/railties/databases.rake +26 -38
  122. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  123. data/lib/active_record/railties/job_runtime.rb +10 -11
  124. data/lib/active_record/reflection.rb +53 -21
  125. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  126. data/lib/active_record/relation/batches.rb +147 -73
  127. data/lib/active_record/relation/calculations.rb +52 -40
  128. data/lib/active_record/relation/delegation.rb +25 -15
  129. data/lib/active_record/relation/finder_methods.rb +40 -24
  130. data/lib/active_record/relation/merger.rb +8 -8
  131. data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
  132. data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -9
  133. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
  134. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  135. data/lib/active_record/relation/predicate_builder.rb +22 -7
  136. data/lib/active_record/relation/query_attribute.rb +3 -1
  137. data/lib/active_record/relation/query_methods.rb +140 -86
  138. data/lib/active_record/relation/spawn_methods.rb +7 -7
  139. data/lib/active_record/relation/where_clause.rb +2 -9
  140. data/lib/active_record/relation.rb +107 -75
  141. data/lib/active_record/result.rb +109 -24
  142. data/lib/active_record/runtime_registry.rb +42 -58
  143. data/lib/active_record/sanitization.rb +9 -6
  144. data/lib/active_record/schema_dumper.rb +18 -11
  145. data/lib/active_record/schema_migration.rb +2 -1
  146. data/lib/active_record/scoping/named.rb +5 -2
  147. data/lib/active_record/scoping.rb +0 -1
  148. data/lib/active_record/signed_id.rb +43 -15
  149. data/lib/active_record/statement_cache.rb +24 -20
  150. data/lib/active_record/store.rb +51 -22
  151. data/lib/active_record/structured_event_subscriber.rb +85 -0
  152. data/lib/active_record/table_metadata.rb +6 -23
  153. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  154. data/lib/active_record/tasks/database_tasks.rb +85 -85
  155. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
  156. data/lib/active_record/tasks/postgresql_database_tasks.rb +7 -40
  157. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
  158. data/lib/active_record/test_databases.rb +14 -4
  159. data/lib/active_record/test_fixtures.rb +39 -2
  160. data/lib/active_record/testing/query_assertions.rb +8 -2
  161. data/lib/active_record/timestamp.rb +4 -2
  162. data/lib/active_record/token_for.rb +1 -1
  163. data/lib/active_record/transaction.rb +2 -5
  164. data/lib/active_record/transactions.rb +37 -16
  165. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  166. data/lib/active_record/type/internal/timezone.rb +7 -0
  167. data/lib/active_record/type/json.rb +13 -2
  168. data/lib/active_record/type/serialized.rb +16 -4
  169. data/lib/active_record/type/type_map.rb +1 -1
  170. data/lib/active_record/type_caster/connection.rb +2 -1
  171. data/lib/active_record/validations/associated.rb +1 -1
  172. data/lib/active_record/validations/uniqueness.rb +8 -8
  173. data/lib/active_record.rb +84 -49
  174. data/lib/arel/alias_predication.rb +2 -0
  175. data/lib/arel/collectors/bind.rb +2 -2
  176. data/lib/arel/collectors/sql_string.rb +1 -1
  177. data/lib/arel/collectors/substitute_binds.rb +2 -2
  178. data/lib/arel/crud.rb +6 -11
  179. data/lib/arel/nodes/binary.rb +1 -1
  180. data/lib/arel/nodes/count.rb +2 -2
  181. data/lib/arel/nodes/function.rb +4 -10
  182. data/lib/arel/nodes/named_function.rb +2 -2
  183. data/lib/arel/nodes/node.rb +2 -2
  184. data/lib/arel/nodes/sql_literal.rb +1 -1
  185. data/lib/arel/nodes.rb +0 -2
  186. data/lib/arel/predications.rb +1 -3
  187. data/lib/arel/select_manager.rb +7 -2
  188. data/lib/arel/table.rb +3 -7
  189. data/lib/arel/visitors/dot.rb +0 -3
  190. data/lib/arel/visitors/postgresql.rb +55 -0
  191. data/lib/arel/visitors/sqlite.rb +55 -8
  192. data/lib/arel/visitors/to_sql.rb +3 -21
  193. data/lib/arel.rb +3 -1
  194. data/lib/rails/generators/active_record/application_record/USAGE +1 -1
  195. metadata +16 -13
  196. data/lib/active_record/explain_subscriber.rb +0 -34
  197. data/lib/active_record/normalization.rb +0 -163
  198. 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,7 @@ module ActiveRecord
43
43
 
44
44
  attr_reader :pool
45
45
  attr_reader :visitor, :owner, :logger, :lock
46
+ attr_reader :allow_preconnect # :nodoc:
46
47
  attr_accessor :pinned # :nodoc:
47
48
  alias :in_use? :owner
48
49
 
@@ -52,7 +53,11 @@ module ActiveRecord
52
53
  @pool = value
53
54
  end
54
55
 
55
- 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
56
61
 
57
62
  def self.type_cast_config_to_integer(config)
58
63
  if config.is_a?(Integer)
@@ -121,7 +126,7 @@ module ActiveRecord
121
126
 
122
127
  # Opens a database console session.
123
128
  def self.dbconsole(config, options = {})
124
- raise NotImplementedError
129
+ raise NotImplementedError.new("#{self} should define `dbconsole` that accepts a db config and options to implement connecting to the db console")
125
130
  end
126
131
 
127
132
  def initialize(config_or_deprecated_connection, deprecated_logger = nil, deprecated_connection_options = nil, deprecated_config = nil) # :nodoc:
@@ -129,6 +134,7 @@ module ActiveRecord
129
134
 
130
135
  @raw_connection = nil
131
136
  @unconfigured_connection = nil
137
+ @connected_since = nil
132
138
 
133
139
  if config_or_deprecated_connection.is_a?(Hash)
134
140
  @config = config_or_deprecated_connection.symbolize_keys
@@ -141,6 +147,7 @@ module ActiveRecord
141
147
  # Soft-deprecated for now; we'll probably warn in future.
142
148
 
143
149
  @unconfigured_connection = config_or_deprecated_connection
150
+ @connected_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
144
151
  @logger = deprecated_logger || ActiveRecord::Base.logger
145
152
  if deprecated_config
146
153
  @config = (deprecated_config || {}).symbolize_keys
@@ -153,9 +160,9 @@ module ActiveRecord
153
160
 
154
161
  @owner = nil
155
162
  @pinned = false
156
- @instrumenter = ActiveSupport::Notifications.instrumenter
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
@@ -173,6 +180,8 @@ module ActiveRecord
173
180
  @raw_connection_dirty = false
174
181
  @last_activity = nil
175
182
  @verified = false
183
+
184
+ @pool_jitter = rand * max_jitter
176
185
  end
177
186
 
178
187
  def inspect # :nodoc:
@@ -186,31 +195,23 @@ module ActiveRecord
186
195
  @lock =
187
196
  case lock_thread
188
197
  when Thread
189
- ActiveSupport::Concurrency::ThreadLoadInterlockAwareMonitor.new
198
+ ActiveSupport::Concurrency::ThreadMonitor.new
190
199
  when Fiber
191
- ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
200
+ ::Monitor.new
192
201
  else
193
202
  ActiveSupport::Concurrency::NullLock
194
203
  end
195
204
  end
196
205
 
197
- EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
198
- EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze # :nodoc:
199
- private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
200
- def with_instrumenter(instrumenter, &block) # :nodoc:
201
- Thread.handle_interrupt(EXCEPTION_NEVER) do
202
- previous_instrumenter = @instrumenter
203
- @instrumenter = instrumenter
204
- Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
205
- ensure
206
- @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}"
207
209
  end
208
210
  end
209
211
 
210
- def check_if_write_query(sql) # :nodoc:
211
- if preventing_writes? && write_query?(sql)
212
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
213
- end
212
+ MAX_JITTER = 0.0..1.0 # :nodoc:
213
+ def max_jitter
214
+ (@config[:pool_jitter] || 0.2).to_f.clamp(MAX_JITTER)
214
215
  end
215
216
 
216
217
  def replica?
@@ -243,9 +244,9 @@ module ActiveRecord
243
244
  # the value of +current_preventing_writes+.
244
245
  def preventing_writes?
245
246
  return true if replica?
246
- return false if connection_class.nil?
247
+ return false if connection_descriptor.nil?
247
248
 
248
- connection_class.current_preventing_writes
249
+ connection_descriptor.current_preventing_writes
249
250
  end
250
251
 
251
252
  def prepared_statements?
@@ -277,7 +278,11 @@ module ActiveRecord
277
278
  end
278
279
 
279
280
  def valid_type?(type) # :nodoc:
280
- !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
281
286
  end
282
287
 
283
288
  # this method must only be called while holding connection pool's mutex
@@ -296,8 +301,8 @@ module ActiveRecord
296
301
  @owner = ActiveSupport::IsolatedExecutionState.context
297
302
  end
298
303
 
299
- def connection_class # :nodoc:
300
- @pool.connection_class
304
+ def connection_descriptor # :nodoc:
305
+ @pool.connection_descriptor
301
306
  end
302
307
 
303
308
  # The role (e.g. +:writing+) for the current connection. In a
@@ -316,8 +321,12 @@ module ActiveRecord
316
321
  @pool.schema_cache || (@schema_cache ||= BoundSchemaReflection.for_lone_connection(@pool.schema_reflection, self))
317
322
  end
318
323
 
324
+ def pool_jitter(duration)
325
+ duration * (1.0 - @pool_jitter)
326
+ end
327
+
319
328
  # this method must only be called while holding connection pool's mutex
320
- def expire
329
+ def expire(update_idle = true) # :nodoc:
321
330
  if in_use?
322
331
  if @owner != ActiveSupport::IsolatedExecutionState.context
323
332
  raise ActiveRecordError, "Cannot expire connection, " \
@@ -325,8 +334,12 @@ module ActiveRecord
325
334
  "Current thread: #{ActiveSupport::IsolatedExecutionState.context}."
326
335
  end
327
336
 
328
- @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
329
- @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
330
343
  else
331
344
  raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
332
345
  end
@@ -358,6 +371,21 @@ module ActiveRecord
358
371
  end
359
372
  end
360
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
+
361
389
  def unprepared_statement
362
390
  cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements
363
391
  yield
@@ -572,6 +600,10 @@ module ActiveRecord
572
600
  false
573
601
  end
574
602
 
603
+ def supports_disabling_indexes?
604
+ false
605
+ end
606
+
575
607
  def return_value_after_insert?(column) # :nodoc:
576
608
  column.auto_populated?
577
609
  end
@@ -590,23 +622,31 @@ module ActiveRecord
590
622
  end
591
623
 
592
624
  # This is meant to be implemented by the adapters that support custom enum types
593
- def create_enum(*) # :nodoc:
625
+ def create_enum(...) # :nodoc:
594
626
  end
595
627
 
596
628
  # This is meant to be implemented by the adapters that support custom enum types
597
- def drop_enum(*) # :nodoc:
629
+ def drop_enum(...) # :nodoc:
598
630
  end
599
631
 
600
632
  # This is meant to be implemented by the adapters that support custom enum types
601
- def rename_enum(*) # :nodoc:
633
+ def rename_enum(...) # :nodoc:
602
634
  end
603
635
 
604
636
  # This is meant to be implemented by the adapters that support custom enum types
605
- def add_enum_value(*) # :nodoc:
637
+ def add_enum_value(...) # :nodoc:
606
638
  end
607
639
 
608
640
  # This is meant to be implemented by the adapters that support custom enum types
609
- 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:
610
650
  end
611
651
 
612
652
  def advisory_locks_enabled? # :nodoc:
@@ -673,34 +713,36 @@ module ActiveRecord
673
713
  deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline
674
714
 
675
715
  @lock.synchronize do
676
- reconnect
677
-
678
- enable_lazy_transactions!
679
- @raw_connection_dirty = false
680
- @last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
681
- @verified = true
716
+ attempt_configure_connection do
717
+ @allow_preconnect = false
682
718
 
683
- reset_transaction(restore: restore_transactions) do
684
- clear_cache!(new_connection: true)
685
- attempt_configure_connection
686
- end
687
- rescue => original_exception
688
- translated_exception = translate_exception_class(original_exception, nil, nil)
689
- retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
719
+ reconnect
690
720
 
691
- if !retry_deadline_exceeded && retries_available > 0
692
- 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
693
726
 
694
- if retryable_connection_error?(translated_exception)
695
- backoff(connection_retries - retries_available)
696
- retry
727
+ reset_transaction(restore: restore_transactions) do
728
+ clear_cache!(new_connection: true)
729
+ configure_connection
697
730
  end
698
- 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)
699
734
 
700
- @last_activity = nil
701
- @verified = false
735
+ if !retry_deadline_exceeded && retries_available > 0
736
+ retries_available -= 1
737
+
738
+ if retryable_connection_error?(translated_exception)
739
+ backoff(connection_retries - retries_available)
740
+ retry
741
+ end
742
+ end
702
743
 
703
- raise translated_exception
744
+ raise translated_exception
745
+ end
704
746
  end
705
747
  end
706
748
 
@@ -711,6 +753,9 @@ module ActiveRecord
711
753
  clear_cache!(new_connection: true)
712
754
  reset_transaction
713
755
  @raw_connection_dirty = false
756
+ @connected_since = nil
757
+ @last_activity = nil
758
+ @verified = false
714
759
  end
715
760
  end
716
761
 
@@ -733,9 +778,11 @@ module ActiveRecord
733
778
  # should call super immediately after resetting the connection (and while
734
779
  # still holding @lock).
735
780
  def reset!
736
- clear_cache!(new_connection: true)
737
- reset_transaction
738
- attempt_configure_connection
781
+ attempt_configure_connection do
782
+ clear_cache!(new_connection: true)
783
+ reset_transaction
784
+ configure_connection
785
+ end
739
786
  end
740
787
 
741
788
  # Removes the connection from the pool and disconnect it.
@@ -769,11 +816,14 @@ module ActiveRecord
769
816
  unless active?
770
817
  @lock.synchronize do
771
818
  if @unconfigured_connection
772
- @raw_connection = @unconfigured_connection
773
- @unconfigured_connection = nil
774
- attempt_configure_connection
775
- @last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
776
- @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
777
827
  return
778
828
  end
779
829
 
@@ -781,6 +831,7 @@ module ActiveRecord
781
831
  end
782
832
  end
783
833
 
834
+ @last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
784
835
  @verified = true
785
836
  end
786
837
 
@@ -790,8 +841,15 @@ module ActiveRecord
790
841
  end
791
842
 
792
843
  def clean! # :nodoc:
793
- @raw_connection_dirty = false
794
- @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
795
853
  end
796
854
 
797
855
  # Provides access to the underlying database driver for this adapter. For
@@ -879,7 +937,7 @@ module ActiveRecord
879
937
  def register_class_with_precision(mapping, key, klass, **kwargs) # :nodoc:
880
938
  mapping.register_type(key) do |*args|
881
939
  precision = extract_precision(args.last)
882
- klass.new(precision: precision, **kwargs)
940
+ klass.new(precision: precision, **kwargs).freeze
883
941
  end
884
942
  end
885
943
 
@@ -891,6 +949,10 @@ module ActiveRecord
891
949
  end
892
950
  end
893
951
 
952
+ def valid_type?(type) # :nodoc:
953
+ !native_database_types[type].nil?
954
+ end
955
+
894
956
  private
895
957
  def initialize_type_map(m)
896
958
  register_class_with_limit m, %r(boolean)i, Type::Boolean
@@ -910,7 +972,7 @@ module ActiveRecord
910
972
  m.alias_type %r(number)i, "decimal"
911
973
  m.alias_type %r(double)i, "float"
912
974
 
913
- m.register_type %r(^json)i, Type::Json.new
975
+ m.register_type %r(^json)i, Type::Json.new.freeze
914
976
 
915
977
  m.register_type(%r(decimal)i) do |sql_type|
916
978
  scale = extract_scale(sql_type)
@@ -918,9 +980,9 @@ module ActiveRecord
918
980
 
919
981
  if scale == 0
920
982
  # FIXME: Remove this class as well
921
- Type::DecimalWithoutScale.new(precision: precision)
983
+ Type::DecimalWithoutScale.new(precision: precision).freeze
922
984
  else
923
- Type::Decimal.new(precision: precision, scale: scale)
985
+ Type::Decimal.new(precision: precision, scale: scale).freeze
924
986
  end
925
987
  end
926
988
  end
@@ -928,7 +990,7 @@ module ActiveRecord
928
990
  def register_class_with_limit(mapping, key, klass)
929
991
  mapping.register_type(key) do |*args|
930
992
  limit = extract_limit(args.last)
931
- klass.new(limit: limit)
993
+ klass.new(limit: limit).freeze
932
994
  end
933
995
  end
934
996
 
@@ -1066,7 +1128,8 @@ module ActiveRecord
1066
1128
  end
1067
1129
 
1068
1130
  def retryable_connection_error?(exception)
1069
- exception.is_a?(ConnectionNotEstablished) || exception.is_a?(ConnectionFailed)
1131
+ (exception.is_a?(ConnectionNotEstablished) && !exception.is_a?(ConnectionNotDefined)) ||
1132
+ exception.is_a?(ConnectionFailed)
1070
1133
  end
1071
1134
 
1072
1135
  def invalidate_transaction(exception)
@@ -1088,7 +1151,7 @@ module ActiveRecord
1088
1151
  end
1089
1152
 
1090
1153
  def reconnect
1091
- raise NotImplementedError
1154
+ raise NotImplementedError.new("#{self.class} should define `reconnect` to implement adapter-specific logic for reconnecting to the database")
1092
1155
  end
1093
1156
 
1094
1157
  # Returns a raw connection for internal use with methods that are known
@@ -1127,27 +1190,30 @@ module ActiveRecord
1127
1190
  end
1128
1191
  end
1129
1192
 
1130
- def translate_exception_class(e, sql, binds)
1131
- 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)
1132
1195
 
1133
- exception = translate_exception(
1134
- 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
1135
1200
  )
1136
- exception.set_backtrace e.backtrace
1137
- exception
1201
+ active_record_error.set_backtrace(native_error.backtrace)
1202
+ active_record_error
1138
1203
  end
1139
1204
 
1140
- def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false, &block) # :doc:
1141
- @instrumenter.instrument(
1205
+ def log(sql, name = "SQL", binds = [], type_casted_binds = [], async: false, allow_retry: false, &block) # :doc:
1206
+ instrumenter.instrument(
1142
1207
  "sql.active_record",
1143
1208
  sql: sql,
1144
1209
  name: name,
1145
1210
  binds: binds,
1146
1211
  type_casted_binds: type_casted_binds,
1147
- statement_name: statement_name,
1148
1212
  async: async,
1213
+ allow_retry: allow_retry,
1149
1214
  connection: self,
1150
1215
  transaction: current_transaction.user_transaction.presence,
1216
+ affected_rows: 0,
1151
1217
  row_count: 0,
1152
1218
  &block
1153
1219
  )
@@ -1155,11 +1221,8 @@ module ActiveRecord
1155
1221
  raise ex.set_query(sql, binds)
1156
1222
  end
1157
1223
 
1158
- def transform_query(sql)
1159
- ActiveRecord.query_transformers.each do |transformer|
1160
- sql = transformer.call(sql, self)
1161
- end
1162
- sql
1224
+ def instrumenter # :nodoc:
1225
+ ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] ||= ActiveSupport::Notifications.instrumenter
1163
1226
  end
1164
1227
 
1165
1228
  def translate_exception(exception, message:, sql:, binds:)
@@ -1172,10 +1235,6 @@ module ActiveRecord
1172
1235
  end
1173
1236
  end
1174
1237
 
1175
- def without_prepared_statement?(binds)
1176
- !prepared_statements || binds.empty?
1177
- end
1178
-
1179
1238
  def column_for(table_name, column_name)
1180
1239
  column_name = column_name.to_s
1181
1240
  columns(table_name).detect { |c| c.name == column_name } ||
@@ -1228,7 +1287,7 @@ module ActiveRecord
1228
1287
  end
1229
1288
 
1230
1289
  def attempt_configure_connection
1231
- configure_connection
1290
+ yield
1232
1291
  rescue Exception # Need to handle things such as Timeout::ExitException
1233
1292
  disconnect!
1234
1293
  raise