activerecord 7.2.4 → 8.1.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 +1013 -878
- data/README.rdoc +1 -1
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/association.rb +69 -27
- data/lib/active_record/associations/association_scope.rb +1 -1
- data/lib/active_record/associations/belongs_to_association.rb +2 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +36 -8
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +7 -3
- data/lib/active_record/associations/collection_proxy.rb +26 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/foreign_association.rb +3 -1
- data/lib/active_record/associations/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/has_one_association.rb +1 -0
- data/lib/active_record/associations/join_dependency.rb +3 -2
- data/lib/active_record/associations/preloader/association.rb +3 -3
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +1 -0
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +192 -24
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/primary_key.rb +4 -8
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +18 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
- data/lib/active_record/attributes.rb +3 -0
- data/lib/active_record/autosave_association.rb +69 -27
- data/lib/active_record/base.rb +1 -2
- data/lib/active_record/callbacks.rb +1 -2
- data/lib/active_record/coders/column_serializer.rb +1 -1
- data/lib/active_record/coders/json.rb +16 -6
- data/lib/active_record/coders/yaml_column.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +68 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +429 -93
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +148 -74
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +27 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +32 -35
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +124 -34
- data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
- data/lib/active_record/connection_adapters/abstract_adapter.rb +129 -63
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +132 -65
- data/lib/active_record/connection_adapters/column.rb +14 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +79 -66
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -10
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +79 -61
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +46 -3
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +14 -33
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +71 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +156 -68
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +78 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +15 -16
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +104 -37
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +41 -66
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +15 -18
- data/lib/active_record/connection_adapters.rb +1 -56
- data/lib/active_record/connection_handling.rb +25 -2
- data/lib/active_record/core.rb +33 -17
- data/lib/active_record/counter_cache.rb +35 -8
- data/lib/active_record/database_configurations/database_config.rb +9 -1
- data/lib/active_record/database_configurations/hash_config.rb +74 -9
- data/lib/active_record/database_configurations/url_config.rb +15 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +5 -1
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +8 -8
- data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
- data/lib/active_record/encryption/encrypted_fixtures.rb +12 -7
- data/lib/active_record/encryption/encryptor.rb +28 -8
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +9 -2
- data/lib/active_record/enum.rb +33 -30
- data/lib/active_record/errors.rb +33 -9
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +76 -0
- data/lib/active_record/fixtures.rb +2 -4
- data/lib/active_record/future_result.rb +15 -9
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +9 -4
- data/lib/active_record/insert_all.rb +14 -9
- data/lib/active_record/locking/optimistic.rb +8 -1
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +31 -29
- data/lib/active_record/message_pack.rb +13 -0
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +56 -13
- data/lib/active_record/migration/compatibility.rb +37 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +48 -42
- data/lib/active_record/model_schema.rb +40 -15
- data/lib/active_record/nested_attributes.rb +14 -12
- data/lib/active_record/persistence.rb +163 -133
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +100 -52
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +21 -9
- data/lib/active_record/railtie.rb +35 -30
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +26 -38
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +54 -22
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +147 -73
- data/lib/active_record/relation/calculations.rb +60 -43
- data/lib/active_record/relation/delegation.rb +25 -15
- data/lib/active_record/relation/finder_methods.rb +73 -43
- data/lib/active_record/relation/merger.rb +12 -10
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -9
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +23 -8
- data/lib/active_record/relation/query_attribute.rb +3 -1
- data/lib/active_record/relation/query_methods.rb +200 -96
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +2 -9
- data/lib/active_record/relation.rb +127 -87
- data/lib/active_record/result.rb +109 -24
- data/lib/active_record/runtime_registry.rb +42 -58
- data/lib/active_record/sanitization.rb +9 -6
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +17 -10
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/signed_id.rb +44 -16
- data/lib/active_record/statement_cache.rb +24 -20
- data/lib/active_record/store.rb +53 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +6 -23
- data/lib/active_record/tasks/abstract_tasks.rb +83 -0
- data/lib/active_record/tasks/database_tasks.rb +85 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +4 -58
- data/lib/active_record/tasks/postgresql_database_tasks.rb +7 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
- data/lib/active_record/test_databases.rb +18 -4
- data/lib/active_record/test_fixtures.rb +52 -6
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +56 -32
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +13 -2
- data/lib/active_record/type/serialized.rb +16 -4
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +2 -1
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +85 -50
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/crud.rb +6 -11
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/node.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/predications.rb +1 -3
- data/lib/arel/select_manager.rb +7 -2
- data/lib/arel/table.rb +3 -7
- data/lib/arel/visitors/dot.rb +0 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +4 -22
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +15 -12
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -163
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
module ActiveRecord
|
|
4
4
|
# = Active Record Query Cache
|
|
5
5
|
class QueryCache
|
|
6
|
+
# ActiveRecord::Base extends this module, so these methods are available in models.
|
|
6
7
|
module ClassMethods
|
|
7
8
|
# Enable the query cache within the block if Active Record is configured.
|
|
8
9
|
# If it's not, it will execute the given block.
|
|
@@ -20,11 +21,15 @@ module ActiveRecord
|
|
|
20
21
|
end
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
#
|
|
24
|
-
#
|
|
24
|
+
# Runs the block with the query cache disabled.
|
|
25
|
+
#
|
|
26
|
+
# If the query cache was enabled before the block was executed, it is
|
|
27
|
+
# enabled again after it.
|
|
25
28
|
#
|
|
26
|
-
# Set <tt>dirties: false</tt> to prevent query caches on all connections
|
|
27
|
-
# (By default, write operations
|
|
29
|
+
# Set <tt>dirties: false</tt> to prevent query caches on all connections
|
|
30
|
+
# from being cleared by write operations. (By default, write operations
|
|
31
|
+
# dirty all connections' query caches in case they are replicas whose
|
|
32
|
+
# cache would now be outdated.)
|
|
28
33
|
def uncached(dirties: true, &block)
|
|
29
34
|
if connected? || !configurations.empty?
|
|
30
35
|
connection_pool.disable_query_cache(dirties: dirties, &block)
|
|
@@ -34,22 +39,24 @@ module ActiveRecord
|
|
|
34
39
|
end
|
|
35
40
|
end
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
module ExecutorHooks # :nodoc:
|
|
43
|
+
def self.run
|
|
44
|
+
ActiveRecord::Base.connection_handler.each_connection_pool.reject(&:query_cache_enabled).each do |pool|
|
|
45
|
+
next if pool.db_config&.query_cache == false
|
|
46
|
+
pool.enable_query_cache!
|
|
47
|
+
end
|
|
41
48
|
end
|
|
42
|
-
end
|
|
43
49
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
def self.complete(pools)
|
|
51
|
+
pools.each do |pool|
|
|
52
|
+
pool.disable_query_cache!
|
|
53
|
+
pool.clear_query_cache
|
|
54
|
+
end
|
|
48
55
|
end
|
|
49
56
|
end
|
|
50
57
|
|
|
51
|
-
def self.install_executor_hooks(executor = ActiveSupport::Executor)
|
|
52
|
-
executor.register_hook(
|
|
58
|
+
def self.install_executor_hooks(executor = ActiveSupport::Executor) # :nodoc:
|
|
59
|
+
executor.register_hook(ExecutorHooks)
|
|
53
60
|
end
|
|
54
61
|
end
|
|
55
62
|
end
|
|
@@ -69,21 +69,77 @@ module ActiveRecord
|
|
|
69
69
|
#
|
|
70
70
|
# Tag comments can be prepended to the query:
|
|
71
71
|
#
|
|
72
|
-
#
|
|
72
|
+
# config.active_record.query_log_tags_prepend_comment = true
|
|
73
73
|
#
|
|
74
74
|
# For applications where the content will not change during the lifetime of
|
|
75
75
|
# the request or job execution, the tags can be cached for reuse in every query:
|
|
76
76
|
#
|
|
77
77
|
# config.active_record.cache_query_log_tags = true
|
|
78
78
|
module QueryLogs
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
class GetKeyHandler # :nodoc:
|
|
80
|
+
def initialize(name)
|
|
81
|
+
@name = name
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def call(context)
|
|
85
|
+
context[@name]
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
class IdentityHandler # :nodoc:
|
|
90
|
+
def initialize(value)
|
|
91
|
+
@value = value
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def call(_context)
|
|
95
|
+
@value
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class ZeroArityHandler # :nodoc:
|
|
100
|
+
def initialize(proc)
|
|
101
|
+
@proc = proc
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def call(_context)
|
|
105
|
+
@proc.call
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
@taggings = {}.freeze
|
|
110
|
+
@tags = [ :application ].freeze
|
|
111
|
+
@prepend_comment = false
|
|
112
|
+
@cache_query_log_tags = false
|
|
113
|
+
@tags_formatter = false
|
|
114
|
+
|
|
84
115
|
thread_mattr_accessor :cached_comment, instance_accessor: false
|
|
85
116
|
|
|
86
117
|
class << self
|
|
118
|
+
attr_reader :tags, :taggings, :tags_formatter # :nodoc:
|
|
119
|
+
attr_accessor :prepend_comment, :cache_query_log_tags # :nodoc:
|
|
120
|
+
|
|
121
|
+
def taggings=(taggings) # :nodoc:
|
|
122
|
+
@taggings = taggings.freeze
|
|
123
|
+
@handlers = rebuild_handlers
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def tags=(tags) # :nodoc:
|
|
127
|
+
@tags = tags.freeze
|
|
128
|
+
@handlers = rebuild_handlers
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def tags_formatter=(format) # :nodoc:
|
|
132
|
+
@formatter = case format
|
|
133
|
+
when :legacy
|
|
134
|
+
LegacyFormatter
|
|
135
|
+
when :sqlcommenter
|
|
136
|
+
SQLCommenter
|
|
137
|
+
else
|
|
138
|
+
raise ArgumentError, "Formatter is unsupported: #{format}"
|
|
139
|
+
end
|
|
140
|
+
@tags_formatter = format
|
|
141
|
+
end
|
|
142
|
+
|
|
87
143
|
def call(sql, connection) # :nodoc:
|
|
88
144
|
comment = self.comment(connection)
|
|
89
145
|
|
|
@@ -100,36 +156,42 @@ module ActiveRecord
|
|
|
100
156
|
self.cached_comment = nil
|
|
101
157
|
end
|
|
102
158
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
self.tags_formatter =
|
|
106
|
-
case format
|
|
107
|
-
when :legacy
|
|
108
|
-
LegacyFormatter.new
|
|
109
|
-
when :sqlcommenter
|
|
110
|
-
SQLCommenter.new
|
|
111
|
-
else
|
|
112
|
-
raise ArgumentError, "Formatter is unsupported: #{formatter}"
|
|
113
|
-
end
|
|
159
|
+
def query_source_location # :nodoc:
|
|
160
|
+
LogSubscriber.backtrace_cleaner.first_clean_frame
|
|
114
161
|
end
|
|
115
162
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
163
|
+
ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
|
|
164
|
+
|
|
165
|
+
private
|
|
166
|
+
def rebuild_handlers
|
|
167
|
+
handlers = []
|
|
168
|
+
@tags.each do |i|
|
|
169
|
+
if i.is_a?(Hash)
|
|
170
|
+
i.each do |k, v|
|
|
171
|
+
handlers << [k, build_handler(k, v)]
|
|
172
|
+
end
|
|
173
|
+
else
|
|
174
|
+
handlers << [i, build_handler(i)]
|
|
175
|
+
end
|
|
121
176
|
end
|
|
122
|
-
|
|
123
|
-
end
|
|
124
|
-
else
|
|
125
|
-
def query_source_location # :nodoc:
|
|
126
|
-
LogSubscriber.backtrace_cleaner.clean(caller_locations(1).each).first
|
|
177
|
+
handlers.sort_by! { |(key, _)| key.to_s }
|
|
127
178
|
end
|
|
128
|
-
end
|
|
129
179
|
|
|
130
|
-
|
|
180
|
+
def build_handler(name, handler = nil)
|
|
181
|
+
handler ||= @taggings[name]
|
|
182
|
+
if handler.nil?
|
|
183
|
+
GetKeyHandler.new(name)
|
|
184
|
+
elsif handler.respond_to?(:call)
|
|
185
|
+
if handler.arity == 0
|
|
186
|
+
ZeroArityHandler.new(handler)
|
|
187
|
+
else
|
|
188
|
+
handler
|
|
189
|
+
end
|
|
190
|
+
else
|
|
191
|
+
IdentityHandler.new(handler)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
131
194
|
|
|
132
|
-
private
|
|
133
195
|
# Returns an SQL comment +String+ containing the query log tags.
|
|
134
196
|
# Sets and returns a cached comment if <tt>cache_query_log_tags</tt> is +true+.
|
|
135
197
|
def comment(connection)
|
|
@@ -140,10 +202,6 @@ module ActiveRecord
|
|
|
140
202
|
end
|
|
141
203
|
end
|
|
142
204
|
|
|
143
|
-
def formatter
|
|
144
|
-
self.tags_formatter || self.update_formatter(:legacy)
|
|
145
|
-
end
|
|
146
|
-
|
|
147
205
|
def uncached_comment(connection)
|
|
148
206
|
content = tag_content(connection)
|
|
149
207
|
|
|
@@ -153,7 +211,7 @@ module ActiveRecord
|
|
|
153
211
|
end
|
|
154
212
|
|
|
155
213
|
def escape_sql_comment(content)
|
|
156
|
-
# Sanitize a string to appear within
|
|
214
|
+
# Sanitize a string to appear within an SQL comment
|
|
157
215
|
# For compatibility, this also surrounding "/*+", "/*", and "*/"
|
|
158
216
|
# characters, possibly with single surrounding space.
|
|
159
217
|
# Then follows that by replacing any internal "*/" or "/ *" with
|
|
@@ -169,25 +227,15 @@ module ActiveRecord
|
|
|
169
227
|
context = ActiveSupport::ExecutionContext.to_h
|
|
170
228
|
context[:connection] ||= connection
|
|
171
229
|
|
|
172
|
-
pairs =
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
val = if handler.nil?
|
|
177
|
-
context[key]
|
|
178
|
-
elsif handler.respond_to?(:call)
|
|
179
|
-
if handler.arity == 0
|
|
180
|
-
handler.call
|
|
181
|
-
else
|
|
182
|
-
handler.call(context)
|
|
183
|
-
end
|
|
184
|
-
else
|
|
185
|
-
handler
|
|
186
|
-
end
|
|
187
|
-
[key, val] unless val.nil?
|
|
230
|
+
pairs = @handlers.filter_map do |(key, handler)|
|
|
231
|
+
val = handler.call(context)
|
|
232
|
+
@formatter.format(key, val) unless val.nil?
|
|
188
233
|
end
|
|
189
|
-
|
|
234
|
+
@formatter.join(pairs)
|
|
190
235
|
end
|
|
191
236
|
end
|
|
237
|
+
|
|
238
|
+
@handlers = rebuild_handlers
|
|
239
|
+
self.tags_formatter = :legacy
|
|
192
240
|
end
|
|
193
241
|
end
|
|
@@ -2,40 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
module ActiveRecord
|
|
4
4
|
module QueryLogs
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# Formats the key value pairs into a string.
|
|
11
|
-
def format(pairs)
|
|
12
|
-
pairs.map! do |key, value|
|
|
13
|
-
"#{key}#{key_value_separator}#{format_value(value)}"
|
|
14
|
-
end.join(",")
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
private
|
|
18
|
-
attr_reader :key_value_separator
|
|
19
|
-
|
|
20
|
-
def format_value(value)
|
|
21
|
-
value
|
|
5
|
+
module LegacyFormatter # :nodoc:
|
|
6
|
+
class << self
|
|
7
|
+
# Formats the key value pairs into a string.
|
|
8
|
+
def format(key, value)
|
|
9
|
+
"#{key}:#{value}"
|
|
22
10
|
end
|
|
23
|
-
end
|
|
24
11
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
12
|
+
def join(pairs)
|
|
13
|
+
pairs.join(",")
|
|
14
|
+
end
|
|
28
15
|
end
|
|
16
|
+
end
|
|
29
17
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
18
|
+
class SQLCommenter # :nodoc:
|
|
19
|
+
class << self
|
|
20
|
+
def format(key, value)
|
|
21
|
+
"#{key}='#{ERB::Util.url_encode(value)}'"
|
|
22
|
+
end
|
|
34
23
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"'#{ERB::Util.url_encode(value)}'"
|
|
24
|
+
def join(pairs)
|
|
25
|
+
pairs.join(",")
|
|
38
26
|
end
|
|
27
|
+
end
|
|
39
28
|
end
|
|
40
29
|
end
|
|
41
30
|
end
|
|
@@ -17,12 +17,24 @@ module ActiveRecord
|
|
|
17
17
|
:and, :or, :annotate, :optimizer_hints, :extending,
|
|
18
18
|
:having, :create_with, :distinct, :references, :none, :unscope, :merge, :except, :only,
|
|
19
19
|
:count, :average, :minimum, :maximum, :sum, :calculate,
|
|
20
|
-
:pluck, :pick, :ids, :async_ids, :strict_loading, :excluding, :without, :
|
|
20
|
+
:pluck, :pick, :ids, :async_ids, :strict_loading, :excluding, :without, :with_recursive,
|
|
21
21
|
:async_count, :async_average, :async_minimum, :async_maximum, :async_sum, :async_pluck, :async_pick,
|
|
22
22
|
:insert, :insert_all, :insert!, :insert_all!, :upsert, :upsert_all
|
|
23
23
|
].freeze # :nodoc:
|
|
24
24
|
delegate(*QUERYING_METHODS, to: :all)
|
|
25
25
|
|
|
26
|
+
# Add a Common Table Expression (CTE) that you can then reference within another SELECT statement.
|
|
27
|
+
#
|
|
28
|
+
# See ActiveRecord::QueryMethods#with for more information.
|
|
29
|
+
#
|
|
30
|
+
# When given a block, and the Object#with core extension is loaded, this
|
|
31
|
+
# delegates to it instead, temporarily setting the given attributes on the
|
|
32
|
+
# class for the duration of the block and restoring them afterwards.
|
|
33
|
+
def with(...)
|
|
34
|
+
return super if block_given? && defined?(super)
|
|
35
|
+
all.with(...)
|
|
36
|
+
end
|
|
37
|
+
|
|
26
38
|
# Executes a custom SQL query against your database and returns all the results. The results will
|
|
27
39
|
# be returned as an array, with the requested columns encapsulated as attributes of the model you call
|
|
28
40
|
# this method from. For example, if you call <tt>Product.find_by_sql</tt>, then the results will be returned in
|
|
@@ -56,12 +68,10 @@ module ActiveRecord
|
|
|
56
68
|
end
|
|
57
69
|
|
|
58
70
|
# Same as #find_by_sql but perform the query asynchronously and returns an ActiveRecord::Promise.
|
|
59
|
-
def async_find_by_sql(sql, binds = [], preparable: nil, &block)
|
|
60
|
-
|
|
61
|
-
_query_by_sql(c, sql, binds, preparable: preparable, async: true)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
result.then do |result|
|
|
71
|
+
def async_find_by_sql(sql, binds = [], preparable: nil, allow_retry: false, &block)
|
|
72
|
+
with_connection do |c|
|
|
73
|
+
_query_by_sql(c, sql, binds, preparable: preparable, allow_retry: allow_retry, async: true)
|
|
74
|
+
end.then do |result|
|
|
65
75
|
_load_from_sql(result, &block)
|
|
66
76
|
end
|
|
67
77
|
end
|
|
@@ -71,6 +81,8 @@ module ActiveRecord
|
|
|
71
81
|
end
|
|
72
82
|
|
|
73
83
|
def _load_from_sql(result_set, &block) # :nodoc:
|
|
84
|
+
return [] if result_set.empty?
|
|
85
|
+
|
|
74
86
|
column_types = result_set.column_types
|
|
75
87
|
|
|
76
88
|
unless column_types.empty?
|
|
@@ -86,10 +98,10 @@ module ActiveRecord
|
|
|
86
98
|
|
|
87
99
|
message_bus.instrument("instantiation.active_record", payload) do
|
|
88
100
|
if result_set.includes_column?(inheritance_column)
|
|
89
|
-
result_set.map { |record| instantiate(record, column_types, &block) }
|
|
101
|
+
result_set.indexed_rows.map { |record| instantiate(record, column_types, &block) }
|
|
90
102
|
else
|
|
91
103
|
# Instantiate a homogeneous set
|
|
92
|
-
result_set.map { |record| instantiate_instance_of(self, record, column_types, &block) }
|
|
104
|
+
result_set.indexed_rows.map { |record| instantiate_instance_of(self, record, column_types, &block) }
|
|
93
105
|
end
|
|
94
106
|
end
|
|
95
107
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "active_record"
|
|
4
3
|
require "rails"
|
|
4
|
+
require "active_record"
|
|
5
5
|
require "active_support/core_ext/object/try"
|
|
6
6
|
require "active_model/railtie"
|
|
7
7
|
|
|
@@ -35,9 +35,12 @@ module ActiveRecord
|
|
|
35
35
|
config.active_record.query_log_tags = [ :application ]
|
|
36
36
|
config.active_record.query_log_tags_format = :legacy
|
|
37
37
|
config.active_record.cache_query_log_tags = false
|
|
38
|
+
config.active_record.query_log_tags_prepend_comment = false
|
|
38
39
|
config.active_record.raise_on_assign_to_attr_readonly = false
|
|
39
40
|
config.active_record.belongs_to_required_validates_foreign_key = true
|
|
40
41
|
config.active_record.generate_secure_token_on = :create
|
|
42
|
+
config.active_record.use_legacy_signed_id_verifier = :generate_and_verify
|
|
43
|
+
config.active_record.deprecated_associations_options = { mode: :warn, backtrace: false }
|
|
41
44
|
|
|
42
45
|
config.active_record.queues = ActiveSupport::InheritableOptions.new
|
|
43
46
|
|
|
@@ -184,30 +187,6 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
|
184
187
|
end
|
|
185
188
|
end
|
|
186
189
|
|
|
187
|
-
initializer "active_record.warn_on_records_fetched_greater_than" do
|
|
188
|
-
if config.active_record.warn_on_records_fetched_greater_than
|
|
189
|
-
ActiveRecord.deprecator.warn <<~MSG.squish
|
|
190
|
-
`config.active_record.warn_on_records_fetched_greater_than` is deprecated and will be
|
|
191
|
-
removed in Rails 8.0.
|
|
192
|
-
Please subscribe to `sql.active_record` notifications and access the row count field to
|
|
193
|
-
detect large result set sizes.
|
|
194
|
-
MSG
|
|
195
|
-
ActiveSupport.on_load(:active_record) do
|
|
196
|
-
require "active_record/relation/record_fetch_warning"
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
initializer "active_record.sqlite3_deprecated_warning" do
|
|
202
|
-
if config.active_record.key?(:sqlite3_production_warning)
|
|
203
|
-
config.active_record.delete(:sqlite3_production_warning)
|
|
204
|
-
ActiveRecord.deprecator.warn <<~MSG.squish
|
|
205
|
-
The `config.active_record.sqlite3_production_warning` configuration no longer has any effect
|
|
206
|
-
and can be safely removed.
|
|
207
|
-
MSG
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
|
|
211
190
|
initializer "active_record.sqlite3_adapter_strict_strings_by_default" do
|
|
212
191
|
config.after_initialize do
|
|
213
192
|
if config.active_record.sqlite3_adapter_strict_strings_by_default
|
|
@@ -253,10 +232,12 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
|
253
232
|
:query_log_tags,
|
|
254
233
|
:query_log_tags_format,
|
|
255
234
|
:cache_query_log_tags,
|
|
235
|
+
:query_log_tags_prepend_comment,
|
|
256
236
|
:sqlite3_adapter_strict_strings_by_default,
|
|
257
237
|
:check_schema_cache_dump_version,
|
|
258
238
|
:use_schema_cache_dump,
|
|
259
239
|
:postgresql_adapter_decode_dates,
|
|
240
|
+
:use_legacy_signed_id_verifier,
|
|
260
241
|
)
|
|
261
242
|
|
|
262
243
|
configs_used_in_other_initializers.each do |k, v|
|
|
@@ -298,6 +279,13 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
|
298
279
|
end
|
|
299
280
|
end
|
|
300
281
|
|
|
282
|
+
initializer "active_record.job_checkpoints" do
|
|
283
|
+
require "active_record/railties/job_checkpoints"
|
|
284
|
+
ActiveSupport.on_load(:active_job_continuable) do
|
|
285
|
+
prepend ActiveRecord::Railties::JobCheckpoints
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
301
289
|
initializer "active_record.set_reloader_hooks" do
|
|
302
290
|
ActiveSupport.on_load(:active_record) do
|
|
303
291
|
ActiveSupport::Reloader.before_class_unload do
|
|
@@ -343,9 +331,22 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
|
343
331
|
end
|
|
344
332
|
end
|
|
345
333
|
|
|
346
|
-
initializer "active_record.
|
|
347
|
-
|
|
348
|
-
|
|
334
|
+
initializer "active_record.filter_attributes_as_log_parameters" do |app|
|
|
335
|
+
ActiveRecord::FilterAttributeHandler.new(app).enable
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
initializer "active_record.configure_message_verifiers" do |app|
|
|
339
|
+
ActiveRecord.message_verifiers = app.message_verifiers
|
|
340
|
+
|
|
341
|
+
use_legacy_signed_id_verifier = app.config.active_record.use_legacy_signed_id_verifier
|
|
342
|
+
legacy_options = { digest: "SHA256", serializer: JSON, url_safe: true }
|
|
343
|
+
|
|
344
|
+
if use_legacy_signed_id_verifier == :generate_and_verify
|
|
345
|
+
app.message_verifiers.prepend { |salt| legacy_options if salt == "active_record/signed_id" }
|
|
346
|
+
elsif use_legacy_signed_id_verifier == :verify
|
|
347
|
+
app.message_verifiers.rotate { |salt| legacy_options if salt == "active_record/signed_id" }
|
|
348
|
+
elsif use_legacy_signed_id_verifier
|
|
349
|
+
raise ArgumentError, "Unrecognized value for config.active_record.use_legacy_signed_id_verifier: #{use_legacy_signed_id_verifier.inspect}"
|
|
349
350
|
end
|
|
350
351
|
end
|
|
351
352
|
|
|
@@ -390,7 +391,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
|
390
391
|
config.after_initialize do
|
|
391
392
|
if app.config.active_record.query_log_tags_enabled
|
|
392
393
|
ActiveRecord.query_transformers << ActiveRecord::QueryLogs
|
|
393
|
-
ActiveRecord::QueryLogs.taggings.merge
|
|
394
|
+
ActiveRecord::QueryLogs.taggings = ActiveRecord::QueryLogs.taggings.merge(
|
|
394
395
|
application: Rails.application.class.name.split("::").first,
|
|
395
396
|
pid: -> { Process.pid.to_s },
|
|
396
397
|
socket: ->(context) { context[:connection].pool.db_config.socket },
|
|
@@ -405,12 +406,16 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
|
405
406
|
end
|
|
406
407
|
|
|
407
408
|
if app.config.active_record.query_log_tags_format
|
|
408
|
-
ActiveRecord::QueryLogs.
|
|
409
|
+
ActiveRecord::QueryLogs.tags_formatter = app.config.active_record.query_log_tags_format
|
|
409
410
|
end
|
|
410
411
|
|
|
411
412
|
if app.config.active_record.cache_query_log_tags
|
|
412
413
|
ActiveRecord::QueryLogs.cache_query_log_tags = true
|
|
413
414
|
end
|
|
415
|
+
|
|
416
|
+
if app.config.active_record.query_log_tags_prepend_comment
|
|
417
|
+
ActiveRecord::QueryLogs.prepend_comment = true
|
|
418
|
+
end
|
|
414
419
|
end
|
|
415
420
|
end
|
|
416
421
|
end
|
|
@@ -41,11 +41,14 @@ module ActiveRecord
|
|
|
41
41
|
|
|
42
42
|
def cleanup_view_runtime
|
|
43
43
|
if logger && logger.info?
|
|
44
|
-
|
|
44
|
+
runtime_stats = ActiveRecord::RuntimeRegistry.stats
|
|
45
|
+
db_rt_before_render = runtime_stats.reset_runtimes
|
|
45
46
|
self.db_runtime = (db_runtime || 0) + db_rt_before_render
|
|
47
|
+
|
|
46
48
|
runtime = super
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
|
|
50
|
+
queries_rt = runtime_stats.sql_runtime - runtime_stats.async_sql_runtime
|
|
51
|
+
db_rt_after_render = runtime_stats.reset_runtimes
|
|
49
52
|
self.db_runtime += db_rt_after_render
|
|
50
53
|
runtime - queries_rt
|
|
51
54
|
else
|
|
@@ -56,9 +59,11 @@ module ActiveRecord
|
|
|
56
59
|
def append_info_to_payload(payload)
|
|
57
60
|
super
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
payload[:
|
|
61
|
-
payload[:
|
|
62
|
+
runtime_stats = ActiveRecord::RuntimeRegistry.stats
|
|
63
|
+
payload[:db_runtime] = (db_runtime || 0) + runtime_stats.sql_runtime
|
|
64
|
+
payload[:queries_count] = runtime_stats.queries_count
|
|
65
|
+
payload[:cached_queries_count] = runtime_stats.cached_queries_count
|
|
66
|
+
runtime_stats.reset
|
|
62
67
|
end
|
|
63
68
|
end
|
|
64
69
|
end
|