activerecord 6.0.6.1 → 6.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (242) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +764 -942
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -3
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +22 -14
  7. data/lib/active_record/associations/alias_tracker.rb +19 -15
  8. data/lib/active_record/associations/association.rb +39 -27
  9. data/lib/active_record/associations/association_scope.rb +11 -15
  10. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  12. data/lib/active_record/associations/builder/association.rb +9 -3
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +19 -13
  20. data/lib/active_record/associations/collection_proxy.rb +12 -5
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -2
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +29 -14
  26. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +63 -49
  28. data/lib/active_record/associations/preloader/association.rb +13 -5
  29. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  30. data/lib/active_record/associations/preloader.rb +5 -3
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations.rb +114 -11
  33. data/lib/active_record/attribute_assignment.rb +10 -8
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  35. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  36. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  37. data/lib/active_record/attribute_methods/query.rb +3 -6
  38. data/lib/active_record/attribute_methods/read.rb +8 -11
  39. data/lib/active_record/attribute_methods/serialization.rb +4 -4
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  41. data/lib/active_record/attribute_methods/write.rb +12 -20
  42. data/lib/active_record/attribute_methods.rb +52 -48
  43. data/lib/active_record/attributes.rb +27 -7
  44. data/lib/active_record/autosave_association.rb +47 -30
  45. data/lib/active_record/base.rb +2 -14
  46. data/lib/active_record/callbacks.rb +32 -22
  47. data/lib/active_record/coders/yaml_column.rb +2 -24
  48. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +180 -134
  49. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +35 -44
  53. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -24
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +31 -70
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
  61. data/lib/active_record/connection_adapters/column.rb +15 -1
  62. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  63. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
  65. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +33 -6
  68. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  69. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  70. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
  71. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  73. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  74. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  75. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  76. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
  77. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  78. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  79. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -10
  80. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  88. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  91. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  92. data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
  93. data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
  94. data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
  95. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
  96. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  97. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  98. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
  99. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
  100. data/lib/active_record/connection_adapters.rb +50 -0
  101. data/lib/active_record/connection_handling.rb +210 -71
  102. data/lib/active_record/core.rb +214 -58
  103. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  104. data/lib/active_record/database_configurations/database_config.rb +52 -9
  105. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  106. data/lib/active_record/database_configurations/url_config.rb +15 -40
  107. data/lib/active_record/database_configurations.rb +124 -85
  108. data/lib/active_record/delegated_type.rb +209 -0
  109. data/lib/active_record/destroy_association_async_job.rb +36 -0
  110. data/lib/active_record/enum.rb +33 -23
  111. data/lib/active_record/errors.rb +47 -12
  112. data/lib/active_record/explain.rb +9 -4
  113. data/lib/active_record/explain_subscriber.rb +1 -1
  114. data/lib/active_record/fixture_set/file.rb +10 -17
  115. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  116. data/lib/active_record/fixture_set/render_context.rb +1 -1
  117. data/lib/active_record/fixture_set/table_row.rb +2 -2
  118. data/lib/active_record/fixtures.rb +54 -8
  119. data/lib/active_record/gem_version.rb +3 -3
  120. data/lib/active_record/inheritance.rb +40 -18
  121. data/lib/active_record/insert_all.rb +32 -5
  122. data/lib/active_record/integration.rb +3 -5
  123. data/lib/active_record/internal_metadata.rb +15 -4
  124. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  125. data/lib/active_record/locking/optimistic.rb +13 -16
  126. data/lib/active_record/locking/pessimistic.rb +6 -2
  127. data/lib/active_record/log_subscriber.rb +26 -8
  128. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  129. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  130. data/lib/active_record/middleware/database_selector.rb +4 -1
  131. data/lib/active_record/migration/command_recorder.rb +47 -27
  132. data/lib/active_record/migration/compatibility.rb +67 -17
  133. data/lib/active_record/migration.rb +113 -83
  134. data/lib/active_record/model_schema.rb +88 -42
  135. data/lib/active_record/nested_attributes.rb +2 -3
  136. data/lib/active_record/no_touching.rb +1 -1
  137. data/lib/active_record/persistence.rb +50 -45
  138. data/lib/active_record/query_cache.rb +15 -5
  139. data/lib/active_record/querying.rb +11 -6
  140. data/lib/active_record/railtie.rb +64 -44
  141. data/lib/active_record/railties/databases.rake +253 -98
  142. data/lib/active_record/readonly_attributes.rb +4 -0
  143. data/lib/active_record/reflection.rb +59 -44
  144. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  145. data/lib/active_record/relation/batches.rb +38 -31
  146. data/lib/active_record/relation/calculations.rb +100 -43
  147. data/lib/active_record/relation/finder_methods.rb +44 -14
  148. data/lib/active_record/relation/from_clause.rb +1 -1
  149. data/lib/active_record/relation/merger.rb +20 -23
  150. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  151. data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -2
  152. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
  153. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  154. data/lib/active_record/relation/predicate_builder.rb +57 -33
  155. data/lib/active_record/relation/query_methods.rb +319 -198
  156. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  157. data/lib/active_record/relation/spawn_methods.rb +6 -5
  158. data/lib/active_record/relation/where_clause.rb +104 -57
  159. data/lib/active_record/relation.rb +90 -64
  160. data/lib/active_record/result.rb +41 -33
  161. data/lib/active_record/runtime_registry.rb +2 -2
  162. data/lib/active_record/sanitization.rb +6 -17
  163. data/lib/active_record/schema_dumper.rb +34 -4
  164. data/lib/active_record/schema_migration.rb +0 -4
  165. data/lib/active_record/scoping/named.rb +1 -17
  166. data/lib/active_record/secure_token.rb +16 -8
  167. data/lib/active_record/serialization.rb +5 -3
  168. data/lib/active_record/signed_id.rb +116 -0
  169. data/lib/active_record/statement_cache.rb +20 -4
  170. data/lib/active_record/store.rb +2 -2
  171. data/lib/active_record/suppressor.rb +2 -2
  172. data/lib/active_record/table_metadata.rb +36 -52
  173. data/lib/active_record/tasks/database_tasks.rb +139 -113
  174. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  175. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  176. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  177. data/lib/active_record/test_databases.rb +5 -4
  178. data/lib/active_record/test_fixtures.rb +36 -33
  179. data/lib/active_record/timestamp.rb +4 -6
  180. data/lib/active_record/touch_later.rb +21 -21
  181. data/lib/active_record/transactions.rb +15 -64
  182. data/lib/active_record/type/serialized.rb +6 -2
  183. data/lib/active_record/type.rb +8 -1
  184. data/lib/active_record/type_caster/connection.rb +0 -1
  185. data/lib/active_record/type_caster/map.rb +8 -5
  186. data/lib/active_record/validations/associated.rb +1 -1
  187. data/lib/active_record/validations/numericality.rb +35 -0
  188. data/lib/active_record/validations/uniqueness.rb +24 -4
  189. data/lib/active_record/validations.rb +1 -0
  190. data/lib/active_record.rb +7 -14
  191. data/lib/arel/attributes/attribute.rb +4 -0
  192. data/lib/arel/collectors/bind.rb +5 -0
  193. data/lib/arel/collectors/composite.rb +8 -0
  194. data/lib/arel/collectors/sql_string.rb +7 -0
  195. data/lib/arel/collectors/substitute_binds.rb +7 -0
  196. data/lib/arel/nodes/binary.rb +82 -8
  197. data/lib/arel/nodes/bind_param.rb +8 -0
  198. data/lib/arel/nodes/casted.rb +21 -9
  199. data/lib/arel/nodes/equality.rb +6 -9
  200. data/lib/arel/nodes/grouping.rb +3 -0
  201. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  202. data/lib/arel/nodes/in.rb +8 -1
  203. data/lib/arel/nodes/infix_operation.rb +13 -1
  204. data/lib/arel/nodes/join_source.rb +1 -1
  205. data/lib/arel/nodes/node.rb +7 -6
  206. data/lib/arel/nodes/ordering.rb +27 -0
  207. data/lib/arel/nodes/sql_literal.rb +3 -0
  208. data/lib/arel/nodes/table_alias.rb +7 -3
  209. data/lib/arel/nodes/unary.rb +0 -1
  210. data/lib/arel/nodes.rb +3 -1
  211. data/lib/arel/predications.rb +12 -18
  212. data/lib/arel/select_manager.rb +1 -2
  213. data/lib/arel/table.rb +13 -5
  214. data/lib/arel/visitors/dot.rb +14 -2
  215. data/lib/arel/visitors/mysql.rb +11 -1
  216. data/lib/arel/visitors/postgresql.rb +15 -4
  217. data/lib/arel/visitors/to_sql.rb +89 -78
  218. data/lib/arel/visitors.rb +0 -7
  219. data/lib/arel.rb +5 -13
  220. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  221. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  222. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  223. data/lib/rails/generators/active_record/migration.rb +6 -1
  224. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  225. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  226. metadata +30 -32
  227. data/lib/active_record/advisory_lock_base.rb +0 -18
  228. data/lib/active_record/attribute_decorators.rb +0 -88
  229. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  230. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  231. data/lib/active_record/define_callbacks.rb +0 -22
  232. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  233. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  234. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  235. data/lib/arel/attributes.rb +0 -22
  236. data/lib/arel/visitors/depth_first.rb +0 -203
  237. data/lib/arel/visitors/ibm_db.rb +0 -34
  238. data/lib/arel/visitors/informix.rb +0 -62
  239. data/lib/arel/visitors/mssql.rb +0 -156
  240. data/lib/arel/visitors/oracle.rb +0 -158
  241. data/lib/arel/visitors/oracle12.rb +0 -65
  242. data/lib/arel/visitors/where_sql.rb +0 -22
@@ -6,38 +6,23 @@ require "monitor"
6
6
  require "weakref"
7
7
 
8
8
  module ActiveRecord
9
- # Raised when a connection could not be obtained within the connection
10
- # acquisition timeout period: because max connections in pool
11
- # are in use.
12
- class ConnectionTimeoutError < ConnectionNotEstablished
13
- end
14
-
15
- # Raised when a pool was unable to get ahold of all its connections
16
- # to perform a "group" action such as
17
- # {ActiveRecord::Base.connection_pool.disconnect!}[rdoc-ref:ConnectionAdapters::ConnectionPool#disconnect!]
18
- # or {ActiveRecord::Base.clear_reloadable_connections!}[rdoc-ref:ConnectionAdapters::ConnectionHandler#clear_reloadable_connections!].
19
- class ExclusiveConnectionTimeoutError < ConnectionTimeoutError
20
- end
21
-
22
9
  module ConnectionAdapters
23
10
  module AbstractPool # :nodoc:
24
11
  def get_schema_cache(connection)
25
- @schema_cache ||= SchemaCache.new(connection)
26
- @schema_cache.connection = connection
27
- @schema_cache
12
+ self.schema_cache ||= SchemaCache.new(connection)
13
+ schema_cache.connection = connection
14
+ schema_cache
28
15
  end
29
16
 
30
17
  def set_schema_cache(cache)
31
- @schema_cache = cache
18
+ self.schema_cache = cache
32
19
  end
33
20
  end
34
21
 
35
22
  class NullPool # :nodoc:
36
23
  include ConnectionAdapters::AbstractPool
37
24
 
38
- def initialize
39
- @schema_cache = nil
40
- end
25
+ attr_accessor :schema_cache
41
26
  end
42
27
 
43
28
  # Connection pool base class for managing Active Record database
@@ -150,7 +135,7 @@ module ActiveRecord
150
135
 
151
136
  # Remove the head of the queue.
152
137
  #
153
- # If +timeout+ is not given, remove and return the head the
138
+ # If +timeout+ is not given, remove and return the head of the
154
139
  # queue if the number of available elements is strictly
155
140
  # greater than the number of threads currently waiting (that
156
141
  # is, don't jump ahead in line). Otherwise, return +nil+.
@@ -193,7 +178,7 @@ module ActiveRecord
193
178
  @queue.pop
194
179
  end
195
180
 
196
- # Remove and return the head the queue if the number of
181
+ # Remove and return the head of the queue if the number of
197
182
  # available elements is strictly greater than the number of
198
183
  # threads currently waiting. Otherwise, return +nil+.
199
184
  def no_wait_poll
@@ -332,11 +317,17 @@ module ActiveRecord
332
317
  private
333
318
  def spawn_thread(frequency)
334
319
  Thread.new(frequency) do |t|
320
+ # Advise multi-threaded app servers to ignore this thread for
321
+ # the purposes of fork safety warnings
322
+ Thread.current.thread_variable_set(:fork_safe, true)
335
323
  running = true
336
324
  while running
337
325
  sleep t
338
326
  @mutex.synchronize do
339
- @pools[frequency].select!(&:weakref_alive?)
327
+ @pools[frequency].select! do |pool|
328
+ pool.weakref_alive? && !pool.discarded?
329
+ end
330
+
340
331
  @pools[frequency].each do |p|
341
332
  p.reap
342
333
  p.flush
@@ -364,28 +355,26 @@ module ActiveRecord
364
355
  include QueryCache::ConnectionPoolConfiguration
365
356
  include ConnectionAdapters::AbstractPool
366
357
 
367
- attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache
368
- attr_reader :spec, :size, :reaper
358
+ attr_accessor :automatic_reconnect, :checkout_timeout
359
+ attr_reader :db_config, :size, :reaper, :pool_config
369
360
 
370
- # Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
361
+ delegate :schema_cache, :schema_cache=, to: :pool_config
362
+
363
+ # Creates a new ConnectionPool object. +pool_config+ is a PoolConfig
371
364
  # object which describes database connection information (e.g. adapter,
372
365
  # host name, username, password, etc), as well as the maximum size for
373
366
  # this ConnectionPool.
374
367
  #
375
368
  # The default ConnectionPool maximum size is 5.
376
- def initialize(spec)
369
+ def initialize(pool_config)
377
370
  super()
378
371
 
379
- @spec = spec
380
-
381
- @checkout_timeout = (spec.config[:checkout_timeout] && spec.config[:checkout_timeout].to_f) || 5
382
- if @idle_timeout = spec.config.fetch(:idle_timeout, 300)
383
- @idle_timeout = @idle_timeout.to_f
384
- @idle_timeout = nil if @idle_timeout <= 0
385
- end
372
+ @pool_config = pool_config
373
+ @db_config = pool_config.db_config
386
374
 
387
- # default max pool size to 5
388
- @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
375
+ @checkout_timeout = db_config.checkout_timeout
376
+ @idle_timeout = db_config.idle_timeout
377
+ @size = db_config.pool
389
378
 
390
379
  # This variable tracks the cache of threads mapped to reserved connections, with the
391
380
  # sole purpose of speeding up the +connection+ method. It is not the authoritative
@@ -413,10 +402,7 @@ module ActiveRecord
413
402
 
414
403
  @lock_thread = false
415
404
 
416
- # +reaping_frequency+ is configurable mostly for historical reasons, but it could
417
- # also be useful if someone wants a very low +idle_timeout+.
418
- reaping_frequency = spec.config.fetch(:reaping_frequency, 60)
419
- @reaper = Reaper.new(self, reaping_frequency && reaping_frequency.to_f)
405
+ @reaper = Reaper.new(self, db_config.reaping_frequency)
420
406
  @reaper.run
421
407
  end
422
408
 
@@ -498,7 +484,7 @@ module ActiveRecord
498
484
  # Raises:
499
485
  # - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
500
486
  # connections in the pool within a timeout interval (default duration is
501
- # <tt>spec.config[:checkout_timeout] * 2</tt> seconds).
487
+ # <tt>spec.db_config.checkout_timeout * 2</tt> seconds).
502
488
  def disconnect(raise_on_acquisition_timeout = true)
503
489
  with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
504
490
  synchronize do
@@ -519,7 +505,7 @@ module ActiveRecord
519
505
  #
520
506
  # The pool first tries to gain ownership of all connections. If unable to
521
507
  # do so within a timeout interval (default duration is
522
- # <tt>spec.config[:checkout_timeout] * 2</tt> seconds), then the pool is forcefully
508
+ # <tt>spec.db_config.checkout_timeout * 2</tt> seconds), then the pool is forcefully
523
509
  # disconnected without any regard for other connection owning threads.
524
510
  def disconnect!
525
511
  disconnect(false)
@@ -532,7 +518,7 @@ module ActiveRecord
532
518
  # See AbstractAdapter#discard!
533
519
  def discard! # :nodoc:
534
520
  synchronize do
535
- return if @connections.nil? # already discarded
521
+ return if self.discarded?
536
522
  @connections.each do |conn|
537
523
  conn.discard!
538
524
  end
@@ -540,13 +526,17 @@ module ActiveRecord
540
526
  end
541
527
  end
542
528
 
529
+ def discarded? # :nodoc:
530
+ @connections.nil?
531
+ end
532
+
543
533
  # Clears the cache which maps classes and re-connects connections that
544
534
  # require reloading.
545
535
  #
546
536
  # Raises:
547
537
  # - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
548
538
  # connections in the pool within a timeout interval (default duration is
549
- # <tt>spec.config[:checkout_timeout] * 2</tt> seconds).
539
+ # <tt>spec.db_config.checkout_timeout * 2</tt> seconds).
550
540
  def clear_reloadable_connections(raise_on_acquisition_timeout = true)
551
541
  with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
552
542
  synchronize do
@@ -568,7 +558,7 @@ module ActiveRecord
568
558
  #
569
559
  # The pool first tries to gain ownership of all connections. If unable to
570
560
  # do so within a timeout interval (default duration is
571
- # <tt>spec.config[:checkout_timeout] * 2</tt> seconds), then the pool forcefully
561
+ # <tt>spec.db_config.checkout_timeout * 2</tt> seconds), then the pool forcefully
572
562
  # clears the cache and reloads connections without any regard for other
573
563
  # connection owning threads.
574
564
  def clear_reloadable_connections!
@@ -648,7 +638,7 @@ module ActiveRecord
648
638
  # or a thread dies unexpectedly.
649
639
  def reap
650
640
  stale_connections = synchronize do
651
- return unless @connections
641
+ return if self.discarded?
652
642
  @connections.select do |conn|
653
643
  conn.in_use? && !conn.owner.alive?
654
644
  end.each do |conn|
@@ -673,7 +663,7 @@ module ActiveRecord
673
663
  return if minimum_idle.nil?
674
664
 
675
665
  idle_connections = synchronize do
676
- return unless @connections
666
+ return if self.discarded?
677
667
  @connections.select do |conn|
678
668
  !conn.in_use? && conn.seconds_idle >= minimum_idle
679
669
  end.each do |conn|
@@ -884,7 +874,7 @@ module ActiveRecord
884
874
  alias_method :release, :remove_connection_from_thread_cache
885
875
 
886
876
  def new_connection
887
- Base.send(spec.adapter_method, spec.config).tap do |conn|
877
+ Base.public_send(db_config.adapter_method, db_config.configuration_hash).tap do |conn|
888
878
  conn.check_version
889
879
  end
890
880
  end
@@ -988,38 +978,18 @@ module ActiveRecord
988
978
  # should use.
989
979
  #
990
980
  # The ConnectionHandler class is not coupled with the Active models, as it has no knowledge
991
- # about the model. The model needs to pass a specification name to the handler,
981
+ # about the model. The model needs to pass a connection specification name to the handler,
992
982
  # in order to look up the correct connection pool.
993
983
  class ConnectionHandler
994
- def self.create_owner_to_pool # :nodoc:
995
- Concurrent::Map.new(initial_capacity: 2) do |h, k|
996
- # Discard the parent's connection pools immediately; we have no need
997
- # of them
998
- discard_unowned_pools(h)
999
-
1000
- h[k] = Concurrent::Map.new(initial_capacity: 2)
1001
- end
1002
- end
1003
-
1004
- def self.unowned_pool_finalizer(pid_map) # :nodoc:
1005
- lambda do |_|
1006
- discard_unowned_pools(pid_map)
1007
- end
1008
- end
1009
-
1010
- def self.discard_unowned_pools(pid_map) # :nodoc:
1011
- pid_map.each do |pid, pools|
1012
- pools.values.compact.each(&:discard!) unless pid == Process.pid
1013
- end
1014
- end
984
+ FINALIZER = lambda { |_| ActiveSupport::ForkTracker.check! }
985
+ private_constant :FINALIZER
1015
986
 
1016
987
  def initialize
1017
- # These caches are keyed by spec.name (ConnectionSpecification#name).
1018
- @owner_to_pool = ConnectionHandler.create_owner_to_pool
988
+ # These caches are keyed by pool_config.connection_specification_name (PoolConfig#connection_specification_name).
989
+ @owner_to_pool_manager = Concurrent::Map.new(initial_capacity: 2)
1019
990
 
1020
- # Backup finalizer: if the forked child never needed a pool, the above
1021
- # early discard has not occurred
1022
- ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool)
991
+ # Backup finalizer: if the forked child skipped Kernel#fork the early discard has not occurred
992
+ ObjectSpace.define_finalizer self, FINALIZER
1023
993
  end
1024
994
 
1025
995
  def prevent_writes # :nodoc:
@@ -1042,84 +1012,112 @@ module ActiveRecord
1042
1012
  # See `READ_QUERY` for the queries that are blocked by this
1043
1013
  # method.
1044
1014
  def while_preventing_writes(enabled = true)
1015
+ unless ActiveRecord::Base.legacy_connection_handling
1016
+ raise NotImplementedError, "`while_preventing_writes` is only available on the connection_handler with legacy_connection_handling"
1017
+ end
1018
+
1045
1019
  original, self.prevent_writes = self.prevent_writes, enabled
1046
1020
  yield
1047
1021
  ensure
1048
1022
  self.prevent_writes = original
1049
1023
  end
1050
1024
 
1051
- def connection_pool_list
1052
- owner_to_pool.values.compact
1025
+ def connection_pool_names # :nodoc:
1026
+ owner_to_pool_manager.keys
1027
+ end
1028
+
1029
+ def all_connection_pools
1030
+ owner_to_pool_manager.values.flat_map { |m| m.pool_configs.map(&:pool) }
1031
+ end
1032
+
1033
+ def connection_pool_list(role = ActiveRecord::Base.current_role)
1034
+ owner_to_pool_manager.values.flat_map { |m| m.pool_configs(role).map(&:pool) }
1053
1035
  end
1054
1036
  alias :connection_pools :connection_pool_list
1055
1037
 
1056
- def establish_connection(config)
1057
- resolver = ConnectionSpecification::Resolver.new(Base.configurations)
1058
- spec = resolver.spec(config)
1038
+ def establish_connection(config, owner_name: Base.name, role: ActiveRecord::Base.current_role, shard: Base.current_shard)
1039
+ owner_name = config.to_s if config.is_a?(Symbol)
1059
1040
 
1060
- remove_connection(spec.name)
1041
+ pool_config = resolve_pool_config(config, owner_name)
1042
+ db_config = pool_config.db_config
1043
+
1044
+ # Protects the connection named `ActiveRecord::Base` from being removed
1045
+ # if the user calls `establish_connection :primary`.
1046
+ if owner_to_pool_manager.key?(pool_config.connection_specification_name)
1047
+ remove_connection_pool(pool_config.connection_specification_name, role: role, shard: shard)
1048
+ end
1061
1049
 
1062
1050
  message_bus = ActiveSupport::Notifications.instrumenter
1063
- payload = {
1064
- connection_id: object_id
1065
- }
1066
- if spec
1067
- payload[:spec_name] = spec.name
1068
- payload[:config] = spec.config
1051
+ payload = {}
1052
+ if pool_config
1053
+ payload[:spec_name] = pool_config.connection_specification_name
1054
+ payload[:shard] = shard
1055
+ payload[:config] = db_config.configuration_hash
1069
1056
  end
1070
1057
 
1071
- message_bus.instrument("!connection.active_record", payload) do
1072
- owner_to_pool[spec.name] = ConnectionAdapters::ConnectionPool.new(spec)
1058
+ if ActiveRecord::Base.legacy_connection_handling
1059
+ owner_to_pool_manager[pool_config.connection_specification_name] ||= LegacyPoolManager.new
1060
+ else
1061
+ owner_to_pool_manager[pool_config.connection_specification_name] ||= PoolManager.new
1073
1062
  end
1063
+ pool_manager = get_pool_manager(pool_config.connection_specification_name)
1064
+ pool_manager.set_pool_config(role, shard, pool_config)
1074
1065
 
1075
- owner_to_pool[spec.name]
1066
+ message_bus.instrument("!connection.active_record", payload) do
1067
+ pool_config.pool
1068
+ end
1076
1069
  end
1077
1070
 
1078
1071
  # Returns true if there are any active connections among the connection
1079
1072
  # pools that the ConnectionHandler is managing.
1080
- def active_connections?
1081
- connection_pool_list.any?(&:active_connection?)
1073
+ def active_connections?(role = ActiveRecord::Base.current_role)
1074
+ connection_pool_list(role).any?(&:active_connection?)
1082
1075
  end
1083
1076
 
1084
1077
  # Returns any connections in use by the current thread back to the pool,
1085
1078
  # and also returns connections to the pool cached by threads that are no
1086
1079
  # longer alive.
1087
- def clear_active_connections!
1088
- connection_pool_list.each(&:release_connection)
1080
+ def clear_active_connections!(role = ActiveRecord::Base.current_role)
1081
+ connection_pool_list(role).each(&:release_connection)
1089
1082
  end
1090
1083
 
1091
1084
  # Clears the cache which maps classes.
1092
1085
  #
1093
1086
  # See ConnectionPool#clear_reloadable_connections! for details.
1094
- def clear_reloadable_connections!
1095
- connection_pool_list.each(&:clear_reloadable_connections!)
1087
+ def clear_reloadable_connections!(role = ActiveRecord::Base.current_role)
1088
+ connection_pool_list(role).each(&:clear_reloadable_connections!)
1096
1089
  end
1097
1090
 
1098
- def clear_all_connections!
1099
- connection_pool_list.each(&:disconnect!)
1091
+ def clear_all_connections!(role = ActiveRecord::Base.current_role)
1092
+ connection_pool_list(role).each(&:disconnect!)
1100
1093
  end
1101
1094
 
1102
1095
  # Disconnects all currently idle connections.
1103
1096
  #
1104
1097
  # See ConnectionPool#flush! for details.
1105
- def flush_idle_connections!
1106
- connection_pool_list.each(&:flush!)
1098
+ def flush_idle_connections!(role = ActiveRecord::Base.current_role)
1099
+ connection_pool_list(role).each(&:flush!)
1107
1100
  end
1108
1101
 
1109
1102
  # Locate the connection of the nearest super class. This can be an
1110
1103
  # active or defined connection: if it is the latter, it will be
1111
1104
  # opened and set as the active connection for the class it was defined
1112
1105
  # for (not necessarily the current class).
1113
- def retrieve_connection(spec_name) #:nodoc:
1114
- pool = retrieve_connection_pool(spec_name)
1106
+ def retrieve_connection(spec_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) # :nodoc:
1107
+ pool = retrieve_connection_pool(spec_name, role: role, shard: shard)
1115
1108
 
1116
1109
  unless pool
1117
- # multiple database application
1118
- if ActiveRecord::Base.connection_handler != ActiveRecord::Base.default_connection_handler
1119
- raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found for the '#{ActiveRecord::Base.current_role}' role."
1110
+ if shard != ActiveRecord::Base.default_shard
1111
+ message = "No connection pool for '#{spec_name}' found for the '#{shard}' shard."
1112
+ elsif ActiveRecord::Base.connection_handler != ActiveRecord::Base.default_connection_handler
1113
+ message = "No connection pool for '#{spec_name}' found for the '#{ActiveRecord::Base.current_role}' role."
1114
+ elsif role != ActiveRecord::Base.default_role
1115
+ message = "No connection pool for '#{spec_name}' found for the '#{role}' role."
1120
1116
  else
1121
- raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found."
1117
+ message = "No connection pool for '#{spec_name}' found."
1122
1118
  end
1119
+
1120
+ raise ConnectionNotEstablished, message
1123
1121
  end
1124
1122
 
1125
1123
  pool.connection
@@ -1127,8 +1125,8 @@ module ActiveRecord
1127
1125
 
1128
1126
  # Returns true if a connection that's accessible to this class has
1129
1127
  # already been opened.
1130
- def connected?(spec_name)
1131
- pool = retrieve_connection_pool(spec_name)
1128
+ def connected?(spec_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
1129
+ pool = retrieve_connection_pool(spec_name, role: role, shard: shard)
1132
1130
  pool && pool.connected?
1133
1131
  end
1134
1132
 
@@ -1136,42 +1134,90 @@ module ActiveRecord
1136
1134
  # connection and the defined connection (if they exist). The result
1137
1135
  # can be used as an argument for #establish_connection, for easily
1138
1136
  # re-establishing the connection.
1139
- def remove_connection(spec_name)
1140
- if pool = owner_to_pool.delete(spec_name)
1141
- pool.automatic_reconnect = false
1142
- pool.disconnect!
1143
- pool.spec.config
1137
+ def remove_connection(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
1138
+ remove_connection_pool(owner, role: role, shard: shard)&.configuration_hash
1139
+ end
1140
+ deprecate remove_connection: "Use #remove_connection_pool, which now returns a DatabaseConfig object instead of a Hash"
1141
+
1142
+ def remove_connection_pool(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
1143
+ if pool_manager = get_pool_manager(owner)
1144
+ pool_config = pool_manager.remove_pool_config(role, shard)
1145
+
1146
+ if pool_config
1147
+ pool_config.disconnect!
1148
+ pool_config.db_config
1149
+ end
1144
1150
  end
1145
1151
  end
1146
1152
 
1147
- # Retrieving the connection pool happens a lot, so we cache it in @owner_to_pool.
1153
+ # Retrieving the connection pool happens a lot, so we cache it in @owner_to_pool_manager.
1148
1154
  # This makes retrieving the connection pool O(1) once the process is warm.
1149
1155
  # When a connection is established or removed, we invalidate the cache.
1150
- def retrieve_connection_pool(spec_name)
1151
- owner_to_pool.fetch(spec_name) do
1152
- # Check if a connection was previously established in an ancestor process,
1153
- # which may have been forked.
1154
- if ancestor_pool = pool_from_any_process_for(spec_name)
1155
- # A connection was established in an ancestor process that must have
1156
- # subsequently forked. We can't reuse the connection, but we can copy
1157
- # the specification and establish a new connection with it.
1158
- establish_connection(ancestor_pool.spec.to_hash).tap do |pool|
1159
- pool.schema_cache = ancestor_pool.schema_cache if ancestor_pool.schema_cache
1160
- end
1161
- else
1162
- owner_to_pool[spec_name] = nil
1163
- end
1164
- end
1156
+ def retrieve_connection_pool(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
1157
+ pool_config = get_pool_manager(owner)&.get_pool_config(role, shard)
1158
+ pool_config&.pool
1165
1159
  end
1166
1160
 
1167
1161
  private
1168
- def owner_to_pool
1169
- @owner_to_pool[Process.pid]
1162
+ attr_reader :owner_to_pool_manager
1163
+
1164
+ # Returns the pool manager for an owner.
1165
+ #
1166
+ # Using `"primary"` to look up the pool manager for `ActiveRecord::Base` is
1167
+ # deprecated in favor of looking it up by `"ActiveRecord::Base"`.
1168
+ #
1169
+ # During the deprecation period, if `"primary"` is passed, the pool manager
1170
+ # for `ActiveRecord::Base` will still be returned.
1171
+ def get_pool_manager(owner)
1172
+ return owner_to_pool_manager[owner] if owner_to_pool_manager.key?(owner)
1173
+
1174
+ if owner == "primary"
1175
+ ActiveSupport::Deprecation.warn("Using `\"primary\"` as a `connection_specification_name` is deprecated and will be removed in Rails 6.2.0. Please use `ActiveRecord::Base`.")
1176
+ owner_to_pool_manager[Base.name]
1177
+ end
1170
1178
  end
1171
1179
 
1172
- def pool_from_any_process_for(spec_name)
1173
- owner_to_pool = @owner_to_pool.values.reverse.find { |v| v[spec_name] }
1174
- owner_to_pool && owner_to_pool[spec_name]
1180
+ # Returns an instance of PoolConfig for a given adapter.
1181
+ # Accepts a hash one layer deep that contains all connection information.
1182
+ #
1183
+ # == Example
1184
+ #
1185
+ # config = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } }
1186
+ # pool_config = Base.configurations.resolve_pool_config(:production)
1187
+ # pool_config.db_config.configuration_hash
1188
+ # # => { host: "localhost", database: "foo", adapter: "sqlite3" }
1189
+ #
1190
+ def resolve_pool_config(config, owner_name)
1191
+ db_config = Base.configurations.resolve(config)
1192
+
1193
+ raise(AdapterNotSpecified, "database configuration does not specify adapter") unless db_config.adapter
1194
+
1195
+ # Require the adapter itself and give useful feedback about
1196
+ # 1. Missing adapter gems and
1197
+ # 2. Adapter gems' missing dependencies.
1198
+ path_to_adapter = "active_record/connection_adapters/#{db_config.adapter}_adapter"
1199
+ begin
1200
+ require path_to_adapter
1201
+ rescue LoadError => e
1202
+ # We couldn't require the adapter itself. Raise an exception that
1203
+ # points out config typos and missing gems.
1204
+ if e.path == path_to_adapter
1205
+ # We can assume that a non-builtin adapter was specified, so it's
1206
+ # either misspelled or missing from Gemfile.
1207
+ raise LoadError, "Could not load the '#{db_config.adapter}' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace
1208
+
1209
+ # Bubbled up from the adapter require. Prefix the exception message
1210
+ # with some guidance about how to address it and reraise.
1211
+ else
1212
+ raise LoadError, "Error loading the '#{db_config.adapter}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
1213
+ end
1214
+ end
1215
+
1216
+ unless ActiveRecord::Base.respond_to?(db_config.adapter_method)
1217
+ raise AdapterNotFound, "database configuration specifies nonexistent #{db_config.adapter} adapter"
1218
+ end
1219
+
1220
+ ConnectionAdapters::PoolConfig.new(owner_name, db_config)
1175
1221
  end
1176
1222
  end
1177
1223
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/deprecation"
4
-
5
3
  module ActiveRecord
6
4
  module ConnectionAdapters # :nodoc:
7
5
  module DatabaseLimits
@@ -14,18 +12,6 @@ module ActiveRecord
14
12
  max_identifier_length
15
13
  end
16
14
 
17
- # Returns the maximum length of a column name.
18
- def column_name_length
19
- max_identifier_length
20
- end
21
- deprecate :column_name_length
22
-
23
- # Returns the maximum length of a table name.
24
- def table_name_length
25
- max_identifier_length
26
- end
27
- deprecate :table_name_length
28
-
29
15
  # Returns the maximum allowed length for an index name. This
30
16
  # limit is enforced by \Rails and is less than or equal to
31
17
  # #index_name_length. The gap between
@@ -34,47 +20,19 @@ module ActiveRecord
34
20
  def allowed_index_name_length
35
21
  index_name_length
36
22
  end
23
+ deprecate :allowed_index_name_length
37
24
 
38
25
  # Returns the maximum length of an index name.
39
26
  def index_name_length
40
27
  max_identifier_length
41
28
  end
42
29
 
43
- # Returns the maximum number of columns per table.
44
- def columns_per_table
45
- 1024
46
- end
47
- deprecate :columns_per_table
48
-
49
- # Returns the maximum number of indexes per table.
50
- def indexes_per_table
51
- 16
52
- end
53
- deprecate :indexes_per_table
54
-
55
- # Returns the maximum number of columns in a multicolumn index.
56
- def columns_per_multicolumn_index
57
- 16
58
- end
59
- deprecate :columns_per_multicolumn_index
60
-
61
30
  # Returns the maximum number of elements in an IN (x,y,z) clause.
62
31
  # +nil+ means no limit.
63
32
  def in_clause_length
64
33
  nil
65
34
  end
66
-
67
- # Returns the maximum length of an SQL query.
68
- def sql_query_length
69
- 1048575
70
- end
71
- deprecate :sql_query_length
72
-
73
- # Returns maximum number of joins in a single query.
74
- def joins_per_query
75
- 256
76
- end
77
- deprecate :joins_per_query
35
+ deprecate :in_clause_length
78
36
 
79
37
  private
80
38
  def bind_params_length