activerecord 7.0.4.3 → 7.1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1657 -1274
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +20 -4
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +16 -10
- data/lib/active_record/associations/collection_proxy.rb +20 -10
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency.rb +10 -8
- data/lib/active_record/associations/preloader/association.rb +31 -7
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +327 -222
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +52 -34
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +18 -5
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +0 -4
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +108 -26
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +55 -9
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +16 -32
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +74 -51
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +129 -31
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +62 -23
- data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +155 -25
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +290 -124
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +509 -102
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +217 -112
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +23 -144
- data/lib/active_record/connection_adapters/mysql/quoting.rb +29 -14
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +18 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +16 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -45
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +15 -8
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +362 -60
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +354 -193
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +52 -39
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +9 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +211 -83
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +262 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +72 -95
- data/lib/active_record/core.rb +175 -153
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +22 -12
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +9 -4
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +2 -0
- data/lib/active_record/disable_joins_association_relation.rb +1 -1
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +42 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +21 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +19 -22
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +112 -28
- data/lib/active_record/errors.rb +112 -18
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +135 -71
- data/lib/active_record/future_result.rb +31 -5
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +57 -10
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +120 -30
- data/lib/active_record/locking/optimistic.rb +32 -18
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +9 -11
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +105 -7
- data/lib/active_record/migration/compatibility.rb +157 -58
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +271 -114
- data/lib/active_record/model_schema.rb +64 -44
- data/lib/active_record/nested_attributes.rb +24 -6
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +195 -42
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +77 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +109 -47
- data/lib/active_record/railties/controller_runtime.rb +14 -9
- data/lib/active_record/railties/databases.rake +142 -148
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +182 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +232 -81
- data/lib/active_record/relation/delegation.rb +23 -9
- data/lib/active_record/relation/finder_methods.rb +77 -16
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +26 -14
- data/lib/active_record/relation/query_attribute.rb +25 -1
- data/lib/active_record/relation/query_methods.rb +387 -71
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +91 -35
- data/lib/active_record/result.rb +25 -9
- data/lib/active_record/runtime_registry.rb +24 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +50 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +7 -5
- data/lib/active_record/store.rb +9 -9
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +127 -105
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_fixtures.rb +113 -96
- data/lib/active_record/timestamp.rb +27 -15
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +39 -13
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +8 -4
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +121 -16
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +1 -1
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/filter.rb +1 -1
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +81 -17
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +48 -12
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -10,35 +10,33 @@ require "active_record/connection_adapters/abstract/connection_pool/reaper"
|
|
10
10
|
module ActiveRecord
|
11
11
|
module ConnectionAdapters
|
12
12
|
module AbstractPool # :nodoc:
|
13
|
-
def get_schema_cache(connection)
|
14
|
-
self.schema_cache ||= SchemaCache.new(connection)
|
15
|
-
schema_cache.connection = connection
|
16
|
-
schema_cache
|
17
|
-
end
|
18
|
-
|
19
|
-
def set_schema_cache(cache)
|
20
|
-
self.schema_cache = cache
|
21
|
-
end
|
22
|
-
|
23
|
-
def lazily_set_schema_cache
|
24
|
-
return unless ActiveRecord.lazily_load_schema_cache
|
25
|
-
|
26
|
-
cache = SchemaCache.load_from(db_config.lazy_schema_cache_path)
|
27
|
-
set_schema_cache(cache)
|
28
|
-
end
|
29
13
|
end
|
30
14
|
|
31
15
|
class NullPool # :nodoc:
|
32
16
|
include ConnectionAdapters::AbstractPool
|
33
17
|
|
34
|
-
|
18
|
+
class NullConfig # :nodoc:
|
19
|
+
def method_missing(*)
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
NULL_CONFIG = NullConfig.new # :nodoc:
|
24
|
+
|
25
|
+
def schema_reflection
|
26
|
+
SchemaReflection.new(nil)
|
27
|
+
end
|
35
28
|
|
36
29
|
def connection_class; end
|
37
30
|
def checkin(_); end
|
38
31
|
def remove(_); end
|
39
32
|
def async_executor; end
|
33
|
+
def db_config
|
34
|
+
NULL_CONFIG
|
35
|
+
end
|
40
36
|
end
|
41
37
|
|
38
|
+
# = Active Record Connection Pool
|
39
|
+
#
|
42
40
|
# Connection pool base class for managing Active Record database
|
43
41
|
# connections.
|
44
42
|
#
|
@@ -53,19 +51,17 @@ module ActiveRecord
|
|
53
51
|
# handle cases in which there are more threads than connections: if all
|
54
52
|
# connections have been checked out, and a thread tries to checkout a
|
55
53
|
# connection anyway, then ConnectionPool will wait until some other thread
|
56
|
-
# has checked in a connection.
|
54
|
+
# has checked in a connection, or the +checkout_timeout+ has expired.
|
57
55
|
#
|
58
56
|
# == Obtaining (checking out) a connection
|
59
57
|
#
|
60
58
|
# Connections can be obtained and used from a connection pool in several
|
61
59
|
# ways:
|
62
60
|
#
|
63
|
-
# 1. Simply use {ActiveRecord::Base.connection}[rdoc-ref:ConnectionHandling.connection]
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
# {ActiveRecord::Base.clear_active_connections!}[rdoc-ref:ConnectionAdapters::ConnectionHandler#clear_active_connections!].
|
68
|
-
# This will be the default behavior for Active Record when used in conjunction with
|
61
|
+
# 1. Simply use {ActiveRecord::Base.connection}[rdoc-ref:ConnectionHandling.connection].
|
62
|
+
# When you're done with the connection(s) and wish it to be returned to the pool, you call
|
63
|
+
# {ActiveRecord::Base.connection_handler.clear_active_connections!}[rdoc-ref:ConnectionAdapters::ConnectionHandler#clear_active_connections!].
|
64
|
+
# This is the default behavior for Active Record when used in conjunction with
|
69
65
|
# Action Pack's request handling cycle.
|
70
66
|
# 2. Manually check out a connection from the pool with
|
71
67
|
# {ActiveRecord::Base.connection_pool.checkout}[rdoc-ref:#checkout]. You are responsible for
|
@@ -78,6 +74,12 @@ module ActiveRecord
|
|
78
74
|
# Connections in the pool are actually AbstractAdapter objects (or objects
|
79
75
|
# compatible with AbstractAdapter's interface).
|
80
76
|
#
|
77
|
+
# While a thread has a connection checked out from the pool using one of the
|
78
|
+
# above three methods, that connection will automatically be the one used
|
79
|
+
# by ActiveRecord queries executing on that thread. It is not required to
|
80
|
+
# explicitly pass the checked out connection to \Rails models or queries, for
|
81
|
+
# example.
|
82
|
+
#
|
81
83
|
# == Options
|
82
84
|
#
|
83
85
|
# There are several connection-pooling-related options that you can add to
|
@@ -105,11 +107,9 @@ module ActiveRecord
|
|
105
107
|
include ConnectionAdapters::AbstractPool
|
106
108
|
|
107
109
|
attr_accessor :automatic_reconnect, :checkout_timeout
|
108
|
-
attr_reader :db_config, :size, :reaper, :pool_config, :
|
110
|
+
attr_reader :db_config, :size, :reaper, :pool_config, :async_executor, :role, :shard
|
109
111
|
|
110
|
-
|
111
|
-
deprecate :connection_klass
|
112
|
-
delegate :schema_cache, :schema_cache=, to: :pool_config
|
112
|
+
delegate :schema_reflection, :schema_reflection=, to: :pool_config
|
113
113
|
|
114
114
|
# Creates a new ConnectionPool object. +pool_config+ is a PoolConfig
|
115
115
|
# object which describes database connection information (e.g. adapter,
|
@@ -122,7 +122,6 @@ module ActiveRecord
|
|
122
122
|
|
123
123
|
@pool_config = pool_config
|
124
124
|
@db_config = pool_config.db_config
|
125
|
-
@connection_class = pool_config.connection_class
|
126
125
|
@role = pool_config.role
|
127
126
|
@shard = pool_config.shard
|
128
127
|
|
@@ -158,18 +157,20 @@ module ActiveRecord
|
|
158
157
|
|
159
158
|
@async_executor = build_async_executor
|
160
159
|
|
161
|
-
lazily_set_schema_cache
|
162
|
-
|
163
160
|
@reaper = Reaper.new(self, db_config.reaping_frequency)
|
164
161
|
@reaper.run
|
165
162
|
end
|
166
163
|
|
167
164
|
def lock_thread=(lock_thread)
|
168
165
|
if lock_thread
|
169
|
-
@lock_thread =
|
166
|
+
@lock_thread = ActiveSupport::IsolatedExecutionState.context
|
170
167
|
else
|
171
168
|
@lock_thread = nil
|
172
169
|
end
|
170
|
+
|
171
|
+
if (active_connection = @thread_cached_conns[connection_cache_key(current_thread)])
|
172
|
+
active_connection.lock_thread = @lock_thread
|
173
|
+
end
|
173
174
|
end
|
174
175
|
|
175
176
|
# Retrieve the connection associated with the current thread, or call
|
@@ -181,6 +182,12 @@ module ActiveRecord
|
|
181
182
|
@thread_cached_conns[connection_cache_key(current_thread)] ||= checkout
|
182
183
|
end
|
183
184
|
|
185
|
+
def connection_class # :nodoc:
|
186
|
+
pool_config.connection_class
|
187
|
+
end
|
188
|
+
alias :connection_klass :connection_class
|
189
|
+
deprecate :connection_klass, deprecator: ActiveRecord.deprecator
|
190
|
+
|
184
191
|
# Returns true if there is an open connection being used for the current thread.
|
185
192
|
#
|
186
193
|
# This method only works for connections that have been obtained through
|
@@ -197,18 +204,23 @@ module ActiveRecord
|
|
197
204
|
# This method only works for connections that have been obtained through
|
198
205
|
# #connection or #with_connection methods, connections obtained through
|
199
206
|
# #checkout will not be automatically released.
|
200
|
-
def release_connection(owner_thread =
|
207
|
+
def release_connection(owner_thread = ActiveSupport::IsolatedExecutionState.context)
|
201
208
|
if conn = @thread_cached_conns.delete(connection_cache_key(owner_thread))
|
202
209
|
checkin conn
|
203
210
|
end
|
204
211
|
end
|
205
212
|
|
206
|
-
#
|
207
|
-
# already
|
208
|
-
#
|
209
|
-
#
|
213
|
+
# Yields a connection from the connection pool to the block. If no connection
|
214
|
+
# is already checked out by the current thread, a connection will be checked
|
215
|
+
# out from the pool, yielded to the block, and then returned to the pool when
|
216
|
+
# the block is finished. If a connection has already been checked out on the
|
217
|
+
# current thread, such as via #connection or #with_connection, that existing
|
218
|
+
# connection will be the one yielded and it will not be returned to the pool
|
219
|
+
# automatically at the end of the block; it is expected that such an existing
|
220
|
+
# connection will be properly returned to the pool by the code that checked
|
221
|
+
# it out.
|
210
222
|
def with_connection
|
211
|
-
unless conn = @thread_cached_conns[connection_cache_key(
|
223
|
+
unless conn = @thread_cached_conns[connection_cache_key(ActiveSupport::IsolatedExecutionState.context)]
|
212
224
|
conn = connection
|
213
225
|
fresh_connection = true
|
214
226
|
end
|
@@ -338,7 +350,9 @@ module ActiveRecord
|
|
338
350
|
# Raises:
|
339
351
|
# - ActiveRecord::ConnectionTimeoutError no connection can be obtained from the pool.
|
340
352
|
def checkout(checkout_timeout = @checkout_timeout)
|
341
|
-
checkout_and_verify(acquire_connection(checkout_timeout))
|
353
|
+
connection = checkout_and_verify(acquire_connection(checkout_timeout))
|
354
|
+
connection.lock_thread = @lock_thread
|
355
|
+
connection
|
342
356
|
end
|
343
357
|
|
344
358
|
# Check-in a database connection back into the pool, indicating that you
|
@@ -355,6 +369,7 @@ module ActiveRecord
|
|
355
369
|
conn.expire
|
356
370
|
end
|
357
371
|
|
372
|
+
conn.lock_thread = nil
|
358
373
|
@available.add conn
|
359
374
|
end
|
360
375
|
end
|
@@ -448,8 +463,7 @@ module ActiveRecord
|
|
448
463
|
@available.num_waiting
|
449
464
|
end
|
450
465
|
|
451
|
-
#
|
452
|
-
# Example:
|
466
|
+
# Returns the connection pool's usage statistic.
|
453
467
|
#
|
454
468
|
# ActiveRecord::Base.connection_pool.stat # => { size: 15, connections: 1, busy: 1, dead: 0, idle: 0, waiting: 0, checkout_timeout: 5 }
|
455
469
|
def stat
|
@@ -510,7 +524,7 @@ module ActiveRecord
|
|
510
524
|
end
|
511
525
|
|
512
526
|
def current_thread
|
513
|
-
@lock_thread ||
|
527
|
+
@lock_thread || ActiveSupport::IsolatedExecutionState.context
|
514
528
|
end
|
515
529
|
|
516
530
|
# Take control of all existing connections so a "group" action such as
|
@@ -527,13 +541,13 @@ module ActiveRecord
|
|
527
541
|
def attempt_to_checkout_all_existing_connections(raise_on_acquisition_timeout = true)
|
528
542
|
collected_conns = synchronize do
|
529
543
|
# account for our own connections
|
530
|
-
@connections.select { |conn| conn.owner ==
|
544
|
+
@connections.select { |conn| conn.owner == ActiveSupport::IsolatedExecutionState.context }
|
531
545
|
end
|
532
546
|
|
533
547
|
newly_checked_out = []
|
534
548
|
timeout_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) + (@checkout_timeout * 2)
|
535
549
|
|
536
|
-
@available.with_a_bias_for(
|
550
|
+
@available.with_a_bias_for(ActiveSupport::IsolatedExecutionState.context) do
|
537
551
|
loop do
|
538
552
|
synchronize do
|
539
553
|
return if collected_conns.size == @connections.size && @now_connecting == 0
|
@@ -580,7 +594,7 @@ module ActiveRecord
|
|
580
594
|
|
581
595
|
thread_report = []
|
582
596
|
@connections.each do |conn|
|
583
|
-
unless conn.owner ==
|
597
|
+
unless conn.owner == ActiveSupport::IsolatedExecutionState.context
|
584
598
|
thread_report << "#{conn} is owned by #{conn.owner}"
|
585
599
|
end
|
586
600
|
end
|
@@ -641,7 +655,13 @@ module ActiveRecord
|
|
641
655
|
conn
|
642
656
|
else
|
643
657
|
reap
|
644
|
-
|
658
|
+
# Retry after reaping, which may return an available connection,
|
659
|
+
# remove an inactive connection, or both
|
660
|
+
if conn = @available.poll || try_to_checkout_new_connection
|
661
|
+
conn
|
662
|
+
else
|
663
|
+
@available.poll(checkout_timeout)
|
664
|
+
end
|
645
665
|
end
|
646
666
|
end
|
647
667
|
|
@@ -653,9 +673,12 @@ module ActiveRecord
|
|
653
673
|
alias_method :release, :remove_connection_from_thread_cache
|
654
674
|
|
655
675
|
def new_connection
|
656
|
-
Base.public_send(db_config.adapter_method, db_config.configuration_hash)
|
657
|
-
|
658
|
-
|
676
|
+
connection = Base.public_send(db_config.adapter_method, db_config.configuration_hash)
|
677
|
+
connection.pool = self
|
678
|
+
connection.check_version
|
679
|
+
connection
|
680
|
+
rescue ConnectionNotEstablished => ex
|
681
|
+
raise ex.set_pool(self)
|
659
682
|
end
|
660
683
|
|
661
684
|
# If the pool is not at a <tt>@size</tt> limit, establish new connection. Connecting
|
@@ -702,10 +725,10 @@ module ActiveRecord
|
|
702
725
|
|
703
726
|
def checkout_and_verify(c)
|
704
727
|
c._run_checkout_callbacks do
|
705
|
-
c.
|
728
|
+
c.clean!
|
706
729
|
end
|
707
730
|
c
|
708
|
-
rescue
|
731
|
+
rescue Exception
|
709
732
|
remove c
|
710
733
|
c.disconnect!
|
711
734
|
raise
|
@@ -15,7 +15,12 @@ module ActiveRecord
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def to_sql_and_binds(arel_or_sql_string, binds = [], preparable = nil) # :nodoc:
|
18
|
+
# Arel::TreeManager -> Arel::Node
|
18
19
|
if arel_or_sql_string.respond_to?(:ast)
|
20
|
+
arel_or_sql_string = arel_or_sql_string.ast
|
21
|
+
end
|
22
|
+
|
23
|
+
if Arel.arel_node?(arel_or_sql_string) && !(String === arel_or_sql_string)
|
19
24
|
unless binds.empty?
|
20
25
|
raise "Passing bind parameters with an arel AST is forbidden. " \
|
21
26
|
"The values must be stored on the AST directly"
|
@@ -25,7 +30,7 @@ module ActiveRecord
|
|
25
30
|
|
26
31
|
if prepared_statements
|
27
32
|
collector.preparable = true
|
28
|
-
sql, binds = visitor.compile(arel_or_sql_string
|
33
|
+
sql, binds = visitor.compile(arel_or_sql_string, collector)
|
29
34
|
|
30
35
|
if binds.length > bind_params_length
|
31
36
|
unprepared_statement do
|
@@ -34,7 +39,7 @@ module ActiveRecord
|
|
34
39
|
end
|
35
40
|
preparable = collector.preparable
|
36
41
|
else
|
37
|
-
sql = visitor.compile(arel_or_sql_string
|
42
|
+
sql = visitor.compile(arel_or_sql_string, collector)
|
38
43
|
end
|
39
44
|
[sql.freeze, binds, preparable]
|
40
45
|
else
|
@@ -65,18 +70,18 @@ module ActiveRecord
|
|
65
70
|
|
66
71
|
select(sql, name, binds, prepare: prepared_statements && preparable, async: async && FutureResult::SelectAll)
|
67
72
|
rescue ::RangeError
|
68
|
-
ActiveRecord::Result.empty
|
73
|
+
ActiveRecord::Result.empty(async: async)
|
69
74
|
end
|
70
75
|
|
71
76
|
# Returns a record hash with the column names as keys and column values
|
72
77
|
# as values.
|
73
|
-
def select_one(arel, name = nil, binds = [])
|
74
|
-
select_all(arel, name, binds).first
|
78
|
+
def select_one(arel, name = nil, binds = [], async: false)
|
79
|
+
select_all(arel, name, binds, async: async).then(&:first)
|
75
80
|
end
|
76
81
|
|
77
82
|
# Returns a single value from a record
|
78
|
-
def select_value(arel, name = nil, binds = [])
|
79
|
-
|
83
|
+
def select_value(arel, name = nil, binds = [], async: false)
|
84
|
+
select_rows(arel, name, binds, async: async).then { |rows| single_value_from_rows(rows) }
|
80
85
|
end
|
81
86
|
|
82
87
|
# Returns an array of the values of the first column in a select:
|
@@ -87,8 +92,8 @@ module ActiveRecord
|
|
87
92
|
|
88
93
|
# Returns an array of arrays containing the field values.
|
89
94
|
# Order is the same as that returned by +columns+.
|
90
|
-
def select_rows(arel, name = nil, binds = [])
|
91
|
-
select_all(arel, name, binds).rows
|
95
|
+
def select_rows(arel, name = nil, binds = [], async: false)
|
96
|
+
select_all(arel, name, binds, async: async).then(&:rows)
|
92
97
|
end
|
93
98
|
|
94
99
|
def query_value(sql, name = nil) # :nodoc:
|
@@ -100,7 +105,7 @@ module ActiveRecord
|
|
100
105
|
end
|
101
106
|
|
102
107
|
def query(sql, name = nil) # :nodoc:
|
103
|
-
|
108
|
+
internal_exec_query(sql, name).rows
|
104
109
|
end
|
105
110
|
|
106
111
|
# Determines whether the SQL statement is a write query.
|
@@ -110,47 +115,63 @@ module ActiveRecord
|
|
110
115
|
|
111
116
|
# Executes the SQL statement in the context of this connection and returns
|
112
117
|
# the raw result from the connection adapter.
|
118
|
+
#
|
119
|
+
# Setting +allow_retry+ to true causes the db to reconnect and retry
|
120
|
+
# executing the SQL statement in case of a connection-related exception.
|
121
|
+
# This option should only be enabled for known idempotent queries.
|
122
|
+
#
|
123
|
+
# Note: the query is assumed to have side effects and the query cache
|
124
|
+
# will be cleared. If the query is read-only, consider using #select_all
|
125
|
+
# instead.
|
126
|
+
#
|
113
127
|
# Note: depending on your database connector, the result returned by this
|
114
|
-
# method may be manually memory managed. Consider using
|
128
|
+
# method may be manually memory managed. Consider using #exec_query
|
115
129
|
# wrapper instead.
|
116
|
-
def execute(sql, name = nil)
|
117
|
-
|
130
|
+
def execute(sql, name = nil, allow_retry: false)
|
131
|
+
internal_execute(sql, name, allow_retry: allow_retry)
|
118
132
|
end
|
119
133
|
|
120
134
|
# Executes +sql+ statement in the context of this connection using
|
121
135
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
122
136
|
# the executed +sql+ statement.
|
137
|
+
#
|
138
|
+
# Note: the query is assumed to have side effects and the query cache
|
139
|
+
# will be cleared. If the query is read-only, consider using #select_all
|
140
|
+
# instead.
|
123
141
|
def exec_query(sql, name = "SQL", binds = [], prepare: false)
|
124
|
-
|
142
|
+
internal_exec_query(sql, name, binds, prepare: prepare)
|
125
143
|
end
|
126
144
|
|
127
145
|
# Executes insert +sql+ statement in the context of this connection using
|
128
146
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
129
147
|
# the executed +sql+ statement.
|
130
|
-
|
131
|
-
|
132
|
-
|
148
|
+
# Some adapters support the `returning` keyword argument which allows to control the result of the query:
|
149
|
+
# `nil` is the default value and maintains default behavior. If an array of column names is passed -
|
150
|
+
# the result will contain values of the specified columns from the inserted row.
|
151
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil)
|
152
|
+
sql, binds = sql_for_insert(sql, pk, binds, returning)
|
153
|
+
internal_exec_query(sql, name, binds)
|
133
154
|
end
|
134
155
|
|
135
156
|
# Executes delete +sql+ statement in the context of this connection using
|
136
157
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
137
158
|
# the executed +sql+ statement.
|
138
159
|
def exec_delete(sql, name = nil, binds = [])
|
139
|
-
|
160
|
+
internal_exec_query(sql, name, binds)
|
140
161
|
end
|
141
162
|
|
142
163
|
# Executes update +sql+ statement in the context of this connection using
|
143
164
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
144
165
|
# the executed +sql+ statement.
|
145
166
|
def exec_update(sql, name = nil, binds = [])
|
146
|
-
|
167
|
+
internal_exec_query(sql, name, binds)
|
147
168
|
end
|
148
169
|
|
149
170
|
def exec_insert_all(sql, name) # :nodoc:
|
150
|
-
|
171
|
+
internal_exec_query(sql, name)
|
151
172
|
end
|
152
173
|
|
153
|
-
def explain(arel, binds = []) # :nodoc:
|
174
|
+
def explain(arel, binds = [], options = []) # :nodoc:
|
154
175
|
raise NotImplementedError
|
155
176
|
end
|
156
177
|
|
@@ -162,9 +183,15 @@ module ActiveRecord
|
|
162
183
|
#
|
163
184
|
# If the next id was calculated in advance (as in Oracle), it should be
|
164
185
|
# passed in as +id_value+.
|
165
|
-
|
186
|
+
# Some adapters support the `returning` keyword argument which allows defining the return value of the method:
|
187
|
+
# `nil` is the default value and maintains default behavior. If an array of column names is passed -
|
188
|
+
# an array of is returned from the method representing values of the specified columns from the inserted row.
|
189
|
+
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil)
|
166
190
|
sql, binds = to_sql_and_binds(arel, binds)
|
167
|
-
value = exec_insert(sql, name, binds, pk, sequence_name)
|
191
|
+
value = exec_insert(sql, name, binds, pk, sequence_name, returning: returning)
|
192
|
+
|
193
|
+
return returning_column_values(value) unless returning.nil?
|
194
|
+
|
168
195
|
id_value || last_inserted_id(value)
|
169
196
|
end
|
170
197
|
alias create insert
|
@@ -187,7 +214,7 @@ module ActiveRecord
|
|
187
214
|
end
|
188
215
|
|
189
216
|
def truncate_tables(*table_names) # :nodoc:
|
190
|
-
table_names -= [schema_migration.table_name,
|
217
|
+
table_names -= [schema_migration.table_name, internal_metadata.table_name]
|
191
218
|
|
192
219
|
return if table_names.empty?
|
193
220
|
|
@@ -304,8 +331,9 @@ module ActiveRecord
|
|
304
331
|
# * You are joining an existing open transaction
|
305
332
|
# * You are creating a nested (savepoint) transaction
|
306
333
|
#
|
307
|
-
# The mysql2 and postgresql adapters support setting the transaction
|
334
|
+
# The mysql2, trilogy, and postgresql adapters support setting the transaction
|
308
335
|
# isolation level.
|
336
|
+
# :args: (requires_new: nil, isolation: nil, &block)
|
309
337
|
def transaction(requires_new: nil, isolation: nil, joinable: true, &block)
|
310
338
|
if !requires_new && current_transaction.joinable?
|
311
339
|
if isolation
|
@@ -323,7 +351,8 @@ module ActiveRecord
|
|
323
351
|
|
324
352
|
delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
|
325
353
|
:commit_transaction, :rollback_transaction, :materialize_transactions,
|
326
|
-
:disable_lazy_transactions!, :enable_lazy_transactions!,
|
354
|
+
:disable_lazy_transactions!, :enable_lazy_transactions!, :dirty_current_transaction,
|
355
|
+
to: :transaction_manager
|
327
356
|
|
328
357
|
def mark_transaction_written_if_write(sql) # :nodoc:
|
329
358
|
transaction = current_transaction
|
@@ -336,8 +365,24 @@ module ActiveRecord
|
|
336
365
|
current_transaction.open?
|
337
366
|
end
|
338
367
|
|
339
|
-
def reset_transaction # :nodoc:
|
368
|
+
def reset_transaction(restore: false) # :nodoc:
|
369
|
+
# Store the existing transaction state to the side
|
370
|
+
old_state = @transaction_manager if restore && @transaction_manager&.restorable?
|
371
|
+
|
340
372
|
@transaction_manager = ConnectionAdapters::TransactionManager.new(self)
|
373
|
+
|
374
|
+
if block_given?
|
375
|
+
# Reconfigure the connection without any transaction state in the way
|
376
|
+
result = yield
|
377
|
+
|
378
|
+
# Now the connection's fully established, we can swap back
|
379
|
+
if old_state
|
380
|
+
@transaction_manager = old_state
|
381
|
+
@transaction_manager.restore_transactions
|
382
|
+
end
|
383
|
+
|
384
|
+
result
|
385
|
+
end
|
341
386
|
end
|
342
387
|
|
343
388
|
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
|
@@ -372,10 +417,18 @@ module ActiveRecord
|
|
372
417
|
# done if the transaction block raises an exception or returns false.
|
373
418
|
def rollback_db_transaction
|
374
419
|
exec_rollback_db_transaction
|
420
|
+
rescue ActiveRecord::ConnectionNotEstablished, ActiveRecord::ConnectionFailed
|
421
|
+
# Connection's gone; that counts as a rollback
|
375
422
|
end
|
376
423
|
|
377
424
|
def exec_rollback_db_transaction() end # :nodoc:
|
378
425
|
|
426
|
+
def restart_db_transaction
|
427
|
+
exec_restart_db_transaction
|
428
|
+
end
|
429
|
+
|
430
|
+
def exec_restart_db_transaction() end # :nodoc:
|
431
|
+
|
379
432
|
def rollback_to_savepoint(name = nil)
|
380
433
|
exec_rollback_to_savepoint(name)
|
381
434
|
end
|
@@ -393,7 +446,7 @@ module ActiveRecord
|
|
393
446
|
# something beyond a simple insert (e.g. Oracle).
|
394
447
|
# Most of adapters should implement +insert_fixtures_set+ that leverages bulk SQL insert.
|
395
448
|
# We keep this method to provide fallback
|
396
|
-
# for databases like
|
449
|
+
# for databases like SQLite that do not support bulk inserts.
|
397
450
|
def insert_fixture(fixture, table_name)
|
398
451
|
execute(build_fixture_sql(Array.wrap(fixture), table_name), "Fixture Insert")
|
399
452
|
end
|
@@ -454,13 +507,30 @@ module ActiveRecord
|
|
454
507
|
HIGH_PRECISION_CURRENT_TIMESTAMP
|
455
508
|
end
|
456
509
|
|
510
|
+
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :nodoc:
|
511
|
+
raise NotImplementedError
|
512
|
+
end
|
513
|
+
|
457
514
|
private
|
515
|
+
def internal_execute(sql, name = "SCHEMA", allow_retry: false, materialize_transactions: true)
|
516
|
+
sql = transform_query(sql)
|
517
|
+
check_if_write_query(sql)
|
518
|
+
|
519
|
+
mark_transaction_written_if_write(sql)
|
520
|
+
|
521
|
+
raw_execute(sql, name, allow_retry: allow_retry, materialize_transactions: materialize_transactions)
|
522
|
+
end
|
523
|
+
|
458
524
|
def execute_batch(statements, name = nil)
|
459
525
|
statements.each do |statement|
|
460
|
-
|
526
|
+
internal_execute(statement, name)
|
461
527
|
end
|
462
528
|
end
|
463
529
|
|
530
|
+
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
|
531
|
+
raise NotImplementedError
|
532
|
+
end
|
533
|
+
|
464
534
|
DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
|
465
535
|
private_constant :DEFAULT_INSERT_VALUE
|
466
536
|
|
@@ -557,10 +627,28 @@ module ActiveRecord
|
|
557
627
|
return future_result
|
558
628
|
end
|
559
629
|
|
560
|
-
|
630
|
+
result = internal_exec_query(sql, name, binds, prepare: prepare)
|
631
|
+
if async
|
632
|
+
FutureResult::Complete.new(result)
|
633
|
+
else
|
634
|
+
result
|
635
|
+
end
|
561
636
|
end
|
562
637
|
|
563
|
-
def sql_for_insert(sql, pk, binds)
|
638
|
+
def sql_for_insert(sql, pk, binds, returning) # :nodoc:
|
639
|
+
if supports_insert_returning?
|
640
|
+
if pk.nil?
|
641
|
+
# Extract the table from the insert sql. Yuck.
|
642
|
+
table_ref = extract_table_ref_from_insert_sql(sql)
|
643
|
+
pk = primary_key(table_ref) if table_ref
|
644
|
+
end
|
645
|
+
|
646
|
+
returning_columns = returning || Array(pk)
|
647
|
+
|
648
|
+
returning_columns_statement = returning_columns.map { |c| quote_column_name(c) }.join(", ")
|
649
|
+
sql = "#{sql} RETURNING #{returning_columns_statement}" if returning_columns.any?
|
650
|
+
end
|
651
|
+
|
564
652
|
[sql, binds]
|
565
653
|
end
|
566
654
|
|
@@ -568,6 +656,10 @@ module ActiveRecord
|
|
568
656
|
single_value_from_rows(result.rows)
|
569
657
|
end
|
570
658
|
|
659
|
+
def returning_column_values(result)
|
660
|
+
[last_inserted_id(result)]
|
661
|
+
end
|
662
|
+
|
571
663
|
def single_value_from_rows(rows)
|
572
664
|
row = rows.first
|
573
665
|
row && row.first
|
@@ -580,6 +672,12 @@ module ActiveRecord
|
|
580
672
|
relation
|
581
673
|
end
|
582
674
|
end
|
675
|
+
|
676
|
+
def extract_table_ref_from_insert_sql(sql)
|
677
|
+
if sql =~ /into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im
|
678
|
+
$1.delete('"').strip
|
679
|
+
end
|
680
|
+
end
|
583
681
|
end
|
584
682
|
end
|
585
683
|
end
|