activerecord 6.0.3.5 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +774 -735
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/active_record.rb +7 -14
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +40 -29
- data/lib/active_record/associations/association_scope.rb +17 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +19 -6
- data/lib/active_record/associations/collection_proxy.rb +13 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency.rb +72 -50
- data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/preloader.rb +11 -5
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods.rb +52 -48
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +4 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attributes.rb +27 -7
- data/lib/active_record/autosave_association.rb +57 -40
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +32 -22
- data/lib/active_record/coders/yaml_column.rb +1 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +186 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +112 -27
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -24
- data/lib/active_record/connection_adapters/abstract_adapter.rb +36 -69
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +129 -88
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +23 -25
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +33 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +11 -7
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +13 -54
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -5
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +31 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +37 -4
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +49 -50
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +220 -55
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +27 -10
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +54 -8
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +33 -6
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +15 -4
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +22 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -8
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/model_schema.rb +88 -13
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/databases.rake +253 -98
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +70 -57
- data/lib/active_record/relation.rb +96 -67
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +101 -44
- data/lib/active_record/relation/delegation.rb +2 -1
- data/lib/active_record/relation/finder_methods.rb +45 -15
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +27 -25
- data/lib/active_record/relation/predicate_builder.rb +57 -33
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +330 -195
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +6 -5
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +0 -4
- data/lib/active_record/scoping/named.rb +6 -17
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +36 -52
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +37 -16
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/arel.rb +5 -13
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +27 -28
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
data/lib/active_record/base.rb
CHANGED
@@ -1,22 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "yaml"
|
4
3
|
require "active_support/benchmarkable"
|
5
4
|
require "active_support/dependencies"
|
6
5
|
require "active_support/descendants_tracker"
|
7
6
|
require "active_support/time"
|
8
|
-
require "active_support/core_ext/module/attribute_accessors"
|
9
|
-
require "active_support/core_ext/array/extract_options"
|
10
|
-
require "active_support/core_ext/hash/deep_merge"
|
11
|
-
require "active_support/core_ext/hash/slice"
|
12
|
-
require "active_support/core_ext/string/behavior"
|
13
|
-
require "active_support/core_ext/kernel/singleton_class"
|
14
|
-
require "active_support/core_ext/module/introspection"
|
15
|
-
require "active_support/core_ext/object/duplicable"
|
16
7
|
require "active_support/core_ext/class/subclasses"
|
17
|
-
require "active_record/attribute_decorators"
|
18
|
-
require "active_record/define_callbacks"
|
19
|
-
require "active_record/errors"
|
20
8
|
require "active_record/log_subscriber"
|
21
9
|
require "active_record/explain_subscriber"
|
22
10
|
require "active_record/relation/delegation"
|
@@ -285,6 +273,7 @@ module ActiveRecord #:nodoc:
|
|
285
273
|
extend Querying
|
286
274
|
extend Translation
|
287
275
|
extend DynamicMatchers
|
276
|
+
extend DelegatedType
|
288
277
|
extend Explain
|
289
278
|
extend Enum
|
290
279
|
extend Delegation::DelegateCache
|
@@ -303,10 +292,8 @@ module ActiveRecord #:nodoc:
|
|
303
292
|
include Validations
|
304
293
|
include CounterCache
|
305
294
|
include Attributes
|
306
|
-
include AttributeDecorators
|
307
295
|
include Locking::Optimistic
|
308
296
|
include Locking::Pessimistic
|
309
|
-
include DefineCallbacks
|
310
297
|
include AttributeMethods
|
311
298
|
include Callbacks
|
312
299
|
include Timestamp
|
@@ -321,6 +308,7 @@ module ActiveRecord #:nodoc:
|
|
321
308
|
include Serialization
|
322
309
|
include Store
|
323
310
|
include SecureToken
|
311
|
+
include SignedId
|
324
312
|
include Suppressor
|
325
313
|
end
|
326
314
|
|
@@ -4,7 +4,7 @@ module ActiveRecord
|
|
4
4
|
# = Active Record \Callbacks
|
5
5
|
#
|
6
6
|
# \Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic
|
7
|
-
# before or after
|
7
|
+
# before or after a change in the object state. This can be used to make sure that associated and
|
8
8
|
# dependent objects are deleted when {ActiveRecord::Base#destroy}[rdoc-ref:Persistence#destroy] is called (by overwriting +before_destroy+) or
|
9
9
|
# to massage attributes before they're validated (by overwriting +before_validation+).
|
10
10
|
# As an example of the callbacks initiated, consider the {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] call for a new record:
|
@@ -32,7 +32,7 @@ module ActiveRecord
|
|
32
32
|
# is found and instantiated by a finder, with <tt>after_initialize</tt> being triggered after new objects
|
33
33
|
# are instantiated as well.
|
34
34
|
#
|
35
|
-
# There are nineteen callbacks in total, which give
|
35
|
+
# There are nineteen callbacks in total, which give a lot of control over how to react and prepare for each state in the
|
36
36
|
# Active Record life cycle. The sequence for calling {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] for an existing record is similar,
|
37
37
|
# except that each <tt>_create</tt> callback is replaced by the corresponding <tt>_update</tt> callback.
|
38
38
|
#
|
@@ -64,7 +64,7 @@ module ActiveRecord
|
|
64
64
|
#
|
65
65
|
# Besides the overwritable callback methods, it's also possible to register callbacks through the
|
66
66
|
# use of the callback macros. Their main advantage is that the macros add behavior into a callback
|
67
|
-
# queue that is kept intact
|
67
|
+
# queue that is kept intact through an inheritance hierarchy.
|
68
68
|
#
|
69
69
|
# class Topic < ActiveRecord::Base
|
70
70
|
# before_destroy :destroy_author
|
@@ -74,7 +74,7 @@ module ActiveRecord
|
|
74
74
|
# before_destroy :destroy_readers
|
75
75
|
# end
|
76
76
|
#
|
77
|
-
#
|
77
|
+
# When <tt>Topic#destroy</tt> is run only +destroy_author+ is called. When <tt>Reply#destroy</tt> is
|
78
78
|
# run, both +destroy_author+ and +destroy_readers+ are called.
|
79
79
|
#
|
80
80
|
# *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the
|
@@ -83,10 +83,9 @@ module ActiveRecord
|
|
83
83
|
#
|
84
84
|
# == Types of callbacks
|
85
85
|
#
|
86
|
-
# There are
|
87
|
-
# inline methods (using a proc). Method references and callback objects
|
88
|
-
#
|
89
|
-
# creating mix-ins).
|
86
|
+
# There are three types of callbacks accepted by the callback macros: method references (symbol), callback objects,
|
87
|
+
# inline methods (using a proc). Method references and callback objects are the recommended approaches,
|
88
|
+
# inline methods using a proc are sometimes appropriate (such as for creating mix-ins).
|
90
89
|
#
|
91
90
|
# The method reference callbacks work by specifying a protected or private method available in the object, like this:
|
92
91
|
#
|
@@ -179,8 +178,8 @@ module ActiveRecord
|
|
179
178
|
#
|
180
179
|
# == Ordering callbacks
|
181
180
|
#
|
182
|
-
# Sometimes
|
183
|
-
# callback (+log_children+ in this case) should be executed before the children
|
181
|
+
# Sometimes application code requires that callbacks execute in a specific order. For example, a +before_destroy+
|
182
|
+
# callback (+log_children+ in this case) should be executed before records in the +children+ association are destroyed by the
|
184
183
|
# <tt>dependent: :destroy</tt> option.
|
185
184
|
#
|
186
185
|
# Let's look at the code below:
|
@@ -196,8 +195,8 @@ module ActiveRecord
|
|
196
195
|
# end
|
197
196
|
# end
|
198
197
|
#
|
199
|
-
# In this case, the problem is that when the +before_destroy+ callback is executed, the children
|
200
|
-
# because the {ActiveRecord::Base#destroy}[rdoc-ref:Persistence#destroy] callback
|
198
|
+
# In this case, the problem is that when the +before_destroy+ callback is executed, records in the +children+ association no
|
199
|
+
# longer exist because the {ActiveRecord::Base#destroy}[rdoc-ref:Persistence#destroy] callback was executed first.
|
201
200
|
# You can use the +prepend+ option on the +before_destroy+ callback to avoid this.
|
202
201
|
#
|
203
202
|
# class Topic < ActiveRecord::Base
|
@@ -211,7 +210,7 @@ module ActiveRecord
|
|
211
210
|
# end
|
212
211
|
# end
|
213
212
|
#
|
214
|
-
# This way, the +before_destroy+
|
213
|
+
# This way, the +before_destroy+ is executed before the <tt>dependent: :destroy</tt> is called, and the data is still available.
|
215
214
|
#
|
216
215
|
# Also, there are cases when you want several callbacks of the same type to
|
217
216
|
# be executed in order.
|
@@ -235,10 +234,10 @@ module ActiveRecord
|
|
235
234
|
# end
|
236
235
|
# end
|
237
236
|
#
|
238
|
-
# In this case the +log_children+
|
237
|
+
# In this case the +log_children+ is executed before +do_something_else+.
|
239
238
|
# The same applies to all non-transactional callbacks.
|
240
239
|
#
|
241
|
-
#
|
240
|
+
# As seen below, in case there are multiple transactional callbacks the order
|
242
241
|
# is reversed.
|
243
242
|
#
|
244
243
|
# For example:
|
@@ -260,16 +259,16 @@ module ActiveRecord
|
|
260
259
|
# end
|
261
260
|
# end
|
262
261
|
#
|
263
|
-
# In this case the +do_something_else+
|
262
|
+
# In this case the +do_something_else+ is executed before +log_children+.
|
264
263
|
#
|
265
264
|
# == \Transactions
|
266
265
|
#
|
267
266
|
# The entire callback chain of a {#save}[rdoc-ref:Persistence#save], {#save!}[rdoc-ref:Persistence#save!],
|
268
267
|
# or {#destroy}[rdoc-ref:Persistence#destroy] call runs within a transaction. That includes <tt>after_*</tt> hooks.
|
269
|
-
# If everything goes fine a COMMIT is executed once the chain has been completed.
|
268
|
+
# If everything goes fine a +COMMIT+ is executed once the chain has been completed.
|
270
269
|
#
|
271
|
-
# If a <tt>before_*</tt> callback cancels the action a ROLLBACK is issued. You
|
272
|
-
# can also trigger a ROLLBACK raising an exception in any of the callbacks,
|
270
|
+
# If a <tt>before_*</tt> callback cancels the action a +ROLLBACK+ is issued. You
|
271
|
+
# can also trigger a +ROLLBACK+ raising an exception in any of the callbacks,
|
273
272
|
# including <tt>after_*</tt> hooks. Note, however, that in that case the client
|
274
273
|
# needs to be aware of it because an ordinary {#save}[rdoc-ref:Persistence#save] will raise such exception
|
275
274
|
# instead of quietly returning +false+.
|
@@ -280,17 +279,17 @@ module ActiveRecord
|
|
280
279
|
# <tt>:before</tt>, <tt>:after</tt> and <tt>:around</tt> as values for the <tt>kind</tt> property. The <tt>kind</tt> property
|
281
280
|
# defines what part of the chain the callback runs in.
|
282
281
|
#
|
283
|
-
# To find all callbacks in the before_save callback chain:
|
282
|
+
# To find all callbacks in the +before_save+ callback chain:
|
284
283
|
#
|
285
284
|
# Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }
|
286
285
|
#
|
287
|
-
# Returns an array of callback objects that form the before_save chain.
|
286
|
+
# Returns an array of callback objects that form the +before_save+ chain.
|
288
287
|
#
|
289
288
|
# To further check if the before_save chain contains a proc defined as <tt>rest_when_dead</tt> use the <tt>filter</tt> property of the callback object:
|
290
289
|
#
|
291
290
|
# Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }.collect(&:filter).include?(:rest_when_dead)
|
292
291
|
#
|
293
|
-
# Returns true or false depending on whether the proc is contained in the before_save callback chain on a Topic model.
|
292
|
+
# Returns true or false depending on whether the proc is contained in the +before_save+ callback chain on a Topic model.
|
294
293
|
#
|
295
294
|
module Callbacks
|
296
295
|
extend ActiveSupport::Concern
|
@@ -302,6 +301,17 @@ module ActiveRecord
|
|
302
301
|
:before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
|
303
302
|
]
|
304
303
|
|
304
|
+
module ClassMethods # :nodoc:
|
305
|
+
include ActiveModel::Callbacks
|
306
|
+
end
|
307
|
+
|
308
|
+
included do
|
309
|
+
include ActiveModel::Validations::Callbacks
|
310
|
+
|
311
|
+
define_model_callbacks :initialize, :find, :touch, only: :after
|
312
|
+
define_model_callbacks :save, :create, :update, :destroy
|
313
|
+
end
|
314
|
+
|
305
315
|
def destroy #:nodoc:
|
306
316
|
@_destroy_callback_already_called ||= false
|
307
317
|
return if @_destroy_callback_already_called
|
@@ -22,7 +22,7 @@ module ActiveRecord
|
|
22
22
|
|
23
23
|
def load(yaml)
|
24
24
|
return object_class.new if object_class != Object && yaml.nil?
|
25
|
-
return yaml unless yaml.is_a?(String) &&
|
25
|
+
return yaml unless yaml.is_a?(String) && yaml.start_with?("---")
|
26
26
|
obj = YAML.load(yaml)
|
27
27
|
|
28
28
|
assert_valid_value(obj, action: "load")
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
extend ActiveSupport::Autoload
|
6
|
+
|
7
|
+
eager_autoload do
|
8
|
+
autoload :AbstractAdapter
|
9
|
+
end
|
10
|
+
|
11
|
+
autoload :Column
|
12
|
+
autoload :PoolConfig
|
13
|
+
autoload :PoolManager
|
14
|
+
autoload :LegacyPoolManager
|
15
|
+
|
16
|
+
autoload_at "active_record/connection_adapters/abstract/schema_definitions" do
|
17
|
+
autoload :IndexDefinition
|
18
|
+
autoload :ColumnDefinition
|
19
|
+
autoload :ChangeColumnDefinition
|
20
|
+
autoload :ForeignKeyDefinition
|
21
|
+
autoload :CheckConstraintDefinition
|
22
|
+
autoload :TableDefinition
|
23
|
+
autoload :Table
|
24
|
+
autoload :AlterTable
|
25
|
+
autoload :ReferenceDefinition
|
26
|
+
end
|
27
|
+
|
28
|
+
autoload_at "active_record/connection_adapters/abstract/connection_pool" do
|
29
|
+
autoload :ConnectionHandler
|
30
|
+
end
|
31
|
+
|
32
|
+
autoload_under "abstract" do
|
33
|
+
autoload :SchemaStatements
|
34
|
+
autoload :DatabaseStatements
|
35
|
+
autoload :DatabaseLimits
|
36
|
+
autoload :Quoting
|
37
|
+
autoload :ConnectionPool
|
38
|
+
autoload :QueryCache
|
39
|
+
autoload :Savepoints
|
40
|
+
end
|
41
|
+
|
42
|
+
autoload_at "active_record/connection_adapters/abstract/transaction" do
|
43
|
+
autoload :TransactionManager
|
44
|
+
autoload :NullTransaction
|
45
|
+
autoload :RealTransaction
|
46
|
+
autoload :SavepointTransaction
|
47
|
+
autoload :TransactionState
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -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
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
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
|
-
|
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!
|
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
|
368
|
-
attr_reader :
|
358
|
+
attr_accessor :automatic_reconnect, :checkout_timeout
|
359
|
+
attr_reader :db_config, :size, :reaper, :pool_config
|
369
360
|
|
370
|
-
|
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(
|
369
|
+
def initialize(pool_config)
|
377
370
|
super()
|
378
371
|
|
379
|
-
@
|
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
|
-
|
388
|
-
@
|
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
|
-
|
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.
|
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.
|
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
|
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.
|
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.
|
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
|
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
|
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.
|
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
|
-
|
995
|
-
|
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
|
1018
|
-
@
|
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
|
1021
|
-
|
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:
|
@@ -1035,85 +1005,119 @@ module ActiveRecord
|
|
1035
1005
|
# In some cases you may want to prevent writes to the database
|
1036
1006
|
# even if you are on a database that can write. `while_preventing_writes`
|
1037
1007
|
# will prevent writes to the database for the duration of the block.
|
1008
|
+
#
|
1009
|
+
# This method does not provide the same protection as a readonly
|
1010
|
+
# user and is meant to be a safeguard against accidental writes.
|
1011
|
+
#
|
1012
|
+
# See `READ_QUERY` for the queries that are blocked by this
|
1013
|
+
# method.
|
1038
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
|
+
|
1039
1019
|
original, self.prevent_writes = self.prevent_writes, enabled
|
1040
1020
|
yield
|
1041
1021
|
ensure
|
1042
1022
|
self.prevent_writes = original
|
1043
1023
|
end
|
1044
1024
|
|
1045
|
-
def
|
1046
|
-
|
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) }
|
1047
1035
|
end
|
1048
1036
|
alias :connection_pools :connection_pool_list
|
1049
1037
|
|
1050
|
-
def establish_connection(config)
|
1051
|
-
|
1052
|
-
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)
|
1053
1040
|
|
1054
|
-
|
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
|
1055
1049
|
|
1056
1050
|
message_bus = ActiveSupport::Notifications.instrumenter
|
1057
|
-
payload = {
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
payload[:
|
1062
|
-
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
|
1063
1056
|
end
|
1064
1057
|
|
1065
|
-
|
1066
|
-
|
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
|
1067
1062
|
end
|
1063
|
+
pool_manager = get_pool_manager(pool_config.connection_specification_name)
|
1064
|
+
pool_manager.set_pool_config(role, shard, pool_config)
|
1068
1065
|
|
1069
|
-
|
1066
|
+
message_bus.instrument("!connection.active_record", payload) do
|
1067
|
+
pool_config.pool
|
1068
|
+
end
|
1070
1069
|
end
|
1071
1070
|
|
1072
1071
|
# Returns true if there are any active connections among the connection
|
1073
1072
|
# pools that the ConnectionHandler is managing.
|
1074
|
-
def active_connections?
|
1075
|
-
connection_pool_list.any?(&:active_connection?)
|
1073
|
+
def active_connections?(role = ActiveRecord::Base.current_role)
|
1074
|
+
connection_pool_list(role).any?(&:active_connection?)
|
1076
1075
|
end
|
1077
1076
|
|
1078
1077
|
# Returns any connections in use by the current thread back to the pool,
|
1079
1078
|
# and also returns connections to the pool cached by threads that are no
|
1080
1079
|
# longer alive.
|
1081
|
-
def clear_active_connections!
|
1082
|
-
connection_pool_list.each(&:release_connection)
|
1080
|
+
def clear_active_connections!(role = ActiveRecord::Base.current_role)
|
1081
|
+
connection_pool_list(role).each(&:release_connection)
|
1083
1082
|
end
|
1084
1083
|
|
1085
1084
|
# Clears the cache which maps classes.
|
1086
1085
|
#
|
1087
1086
|
# See ConnectionPool#clear_reloadable_connections! for details.
|
1088
|
-
def clear_reloadable_connections!
|
1089
|
-
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!)
|
1090
1089
|
end
|
1091
1090
|
|
1092
|
-
def clear_all_connections!
|
1093
|
-
connection_pool_list.each(&:disconnect!)
|
1091
|
+
def clear_all_connections!(role = ActiveRecord::Base.current_role)
|
1092
|
+
connection_pool_list(role).each(&:disconnect!)
|
1094
1093
|
end
|
1095
1094
|
|
1096
1095
|
# Disconnects all currently idle connections.
|
1097
1096
|
#
|
1098
1097
|
# See ConnectionPool#flush! for details.
|
1099
|
-
def flush_idle_connections!
|
1100
|
-
connection_pool_list.each(&:flush!)
|
1098
|
+
def flush_idle_connections!(role = ActiveRecord::Base.current_role)
|
1099
|
+
connection_pool_list(role).each(&:flush!)
|
1101
1100
|
end
|
1102
1101
|
|
1103
1102
|
# Locate the connection of the nearest super class. This can be an
|
1104
1103
|
# active or defined connection: if it is the latter, it will be
|
1105
1104
|
# opened and set as the active connection for the class it was defined
|
1106
1105
|
# for (not necessarily the current class).
|
1107
|
-
def retrieve_connection(spec_name)
|
1108
|
-
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)
|
1109
1108
|
|
1110
1109
|
unless pool
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
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."
|
1114
1116
|
else
|
1115
|
-
|
1117
|
+
message = "No connection pool for '#{spec_name}' found."
|
1116
1118
|
end
|
1119
|
+
|
1120
|
+
raise ConnectionNotEstablished, message
|
1117
1121
|
end
|
1118
1122
|
|
1119
1123
|
pool.connection
|
@@ -1121,8 +1125,8 @@ module ActiveRecord
|
|
1121
1125
|
|
1122
1126
|
# Returns true if a connection that's accessible to this class has
|
1123
1127
|
# already been opened.
|
1124
|
-
def connected?(spec_name)
|
1125
|
-
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)
|
1126
1130
|
pool && pool.connected?
|
1127
1131
|
end
|
1128
1132
|
|
@@ -1130,42 +1134,90 @@ module ActiveRecord
|
|
1130
1134
|
# connection and the defined connection (if they exist). The result
|
1131
1135
|
# can be used as an argument for #establish_connection, for easily
|
1132
1136
|
# re-establishing the connection.
|
1133
|
-
def remove_connection(
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
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
|
1138
1150
|
end
|
1139
1151
|
end
|
1140
1152
|
|
1141
|
-
# Retrieving the connection pool happens a lot, so we cache it in @
|
1153
|
+
# Retrieving the connection pool happens a lot, so we cache it in @owner_to_pool_manager.
|
1142
1154
|
# This makes retrieving the connection pool O(1) once the process is warm.
|
1143
1155
|
# When a connection is established or removed, we invalidate the cache.
|
1144
|
-
def retrieve_connection_pool(
|
1145
|
-
|
1146
|
-
|
1147
|
-
# which may have been forked.
|
1148
|
-
if ancestor_pool = pool_from_any_process_for(spec_name)
|
1149
|
-
# A connection was established in an ancestor process that must have
|
1150
|
-
# subsequently forked. We can't reuse the connection, but we can copy
|
1151
|
-
# the specification and establish a new connection with it.
|
1152
|
-
establish_connection(ancestor_pool.spec.to_hash).tap do |pool|
|
1153
|
-
pool.schema_cache = ancestor_pool.schema_cache if ancestor_pool.schema_cache
|
1154
|
-
end
|
1155
|
-
else
|
1156
|
-
owner_to_pool[spec_name] = nil
|
1157
|
-
end
|
1158
|
-
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
|
1159
1159
|
end
|
1160
1160
|
|
1161
1161
|
private
|
1162
|
-
|
1163
|
-
|
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
|
1164
1178
|
end
|
1165
1179
|
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
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)
|
1169
1221
|
end
|
1170
1222
|
end
|
1171
1223
|
end
|