activerecord 7.2.2.1 → 8.1.2
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 +564 -753
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/association.rb +35 -11
- data/lib/active_record/associations/belongs_to_association.rb +18 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +17 -4
- 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 +10 -8
- data/lib/active_record/associations/collection_proxy.rb +22 -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/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/associations/join_dependency.rb +4 -2
- data/lib/active_record/associations/preloader/association.rb +2 -2
- 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 +17 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
- data/lib/active_record/attribute_methods.rb +24 -19
- data/lib/active_record/attributes.rb +40 -26
- data/lib/active_record/autosave_association.rb +91 -39
- data/lib/active_record/base.rb +3 -4
- data/lib/active_record/coders/json.rb +14 -5
- 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 +51 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +458 -117
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +136 -74
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +44 -11
- 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 +37 -36
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -29
- data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
- data/lib/active_record/connection_adapters/abstract_adapter.rb +175 -87
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +77 -58
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
- 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 +73 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -11
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
- 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/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 +28 -45
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +140 -64
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -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 +13 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +112 -42
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +2 -19
- data/lib/active_record/connection_adapters.rb +1 -56
- data/lib/active_record/connection_handling.rb +37 -10
- data/lib/active_record/core.rb +61 -25
- data/lib/active_record/counter_cache.rb +34 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/database_configurations/database_config.rb +9 -1
- data/lib/active_record/database_configurations/hash_config.rb +67 -9
- data/lib/active_record/database_configurations/url_config.rb +13 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +19 -19
- 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 +9 -9
- data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
- data/lib/active_record/encryption/encryptor.rb +49 -28
- 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 +46 -42
- data/lib/active_record/errors.rb +36 -12
- 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 +73 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +2 -4
- data/lib/active_record/future_result.rb +13 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/insert_all.rb +12 -7
- 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 +3 -13
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +44 -11
- 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 +50 -43
- data/lib/active_record/model_schema.rb +38 -13
- data/lib/active_record/nested_attributes.rb +6 -6
- data/lib/active_record/persistence.rb +162 -133
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +104 -52
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +12 -12
- data/lib/active_record/railtie.rb +37 -32
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +26 -37
- 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 +53 -21
- 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 +80 -63
- data/lib/active_record/relation/delegation.rb +25 -15
- data/lib/active_record/relation/finder_methods.rb +54 -37
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -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 +22 -7
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +156 -95
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +10 -11
- data/lib/active_record/relation.rb +122 -80
- 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_dumper.rb +47 -22
- 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/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +47 -18
- data/lib/active_record/statement_cache.rb +24 -20
- data/lib/active_record/store.rb +51 -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 +76 -0
- data/lib/active_record/tasks/database_tasks.rb +85 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +39 -2
- 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 +39 -16
- 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 +15 -2
- data/lib/active_record/type/serialized.rb +11 -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 +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -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/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/select_manager.rb +13 -4
- data/lib/arel/table.rb +3 -7
- data/lib/arel/update_manager.rb +5 -0
- data/lib/arel/visitors/dot.rb +2 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +6 -22
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +17 -17
- 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
data/lib/active_record/result.rb
CHANGED
|
@@ -29,6 +29,11 @@ module ActiveRecord
|
|
|
29
29
|
# ...
|
|
30
30
|
# ]
|
|
31
31
|
#
|
|
32
|
+
# # Get the number of rows affected by the query:
|
|
33
|
+
# result = ActiveRecord::Base.lease_connection.exec_query('INSERT INTO posts (title, body) VALUES ("title_3", "body_3"), ("title_4", "body_4")')
|
|
34
|
+
# result.affected_rows
|
|
35
|
+
# # => 2
|
|
36
|
+
#
|
|
32
37
|
# # ActiveRecord::Result also includes Enumerable.
|
|
33
38
|
# result.each do |row|
|
|
34
39
|
# puts row['title'] + " " + row['body']
|
|
@@ -36,24 +41,79 @@ module ActiveRecord
|
|
|
36
41
|
class Result
|
|
37
42
|
include Enumerable
|
|
38
43
|
|
|
39
|
-
|
|
44
|
+
class IndexedRow
|
|
45
|
+
def initialize(column_indexes, row)
|
|
46
|
+
@column_indexes = column_indexes
|
|
47
|
+
@row = row
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def size
|
|
51
|
+
@column_indexes.size
|
|
52
|
+
end
|
|
53
|
+
alias_method :length, :size
|
|
54
|
+
|
|
55
|
+
def each_key(&block)
|
|
56
|
+
@column_indexes.each_key(&block)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def keys
|
|
60
|
+
@column_indexes.keys
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def ==(other)
|
|
64
|
+
if other.is_a?(Hash)
|
|
65
|
+
to_hash == other
|
|
66
|
+
else
|
|
67
|
+
super
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def key?(column)
|
|
72
|
+
@column_indexes.key?(column)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def fetch(column)
|
|
76
|
+
if index = @column_indexes[column]
|
|
77
|
+
@row[index]
|
|
78
|
+
elsif block_given?
|
|
79
|
+
yield
|
|
80
|
+
else
|
|
81
|
+
raise KeyError, "key not found: #{column.inspect}"
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def [](column)
|
|
86
|
+
if index = @column_indexes[column]
|
|
87
|
+
@row[index]
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def to_h
|
|
92
|
+
@column_indexes.transform_values { |index| @row[index] }
|
|
93
|
+
end
|
|
94
|
+
alias_method :to_hash, :to_h
|
|
95
|
+
end
|
|
40
96
|
|
|
41
|
-
|
|
97
|
+
attr_reader :columns, :rows, :affected_rows
|
|
98
|
+
|
|
99
|
+
def self.empty(async: false, affected_rows: nil) # :nodoc:
|
|
42
100
|
if async
|
|
43
|
-
|
|
101
|
+
FutureResult.wrap(new(EMPTY_ARRAY, EMPTY_ARRAY, EMPTY_HASH, affected_rows: affected_rows)).freeze
|
|
44
102
|
else
|
|
45
|
-
|
|
103
|
+
new(EMPTY_ARRAY, EMPTY_ARRAY, EMPTY_HASH, affected_rows: affected_rows).freeze
|
|
46
104
|
end
|
|
47
105
|
end
|
|
48
106
|
|
|
49
|
-
def initialize(columns, rows, column_types = nil)
|
|
107
|
+
def initialize(columns, rows, column_types = nil, affected_rows: nil)
|
|
50
108
|
# We freeze the strings to prevent them getting duped when
|
|
51
109
|
# used as keys in ActiveRecord::Base's @attributes hash
|
|
52
110
|
@columns = columns.each(&:-@).freeze
|
|
53
111
|
@rows = rows
|
|
54
112
|
@hash_rows = nil
|
|
55
|
-
@column_types = column_types
|
|
113
|
+
@column_types = column_types.freeze
|
|
114
|
+
@types_hash = nil
|
|
56
115
|
@column_indexes = nil
|
|
116
|
+
@affected_rows = affected_rows
|
|
57
117
|
end
|
|
58
118
|
|
|
59
119
|
# Returns true if this result set includes the column named +name+
|
|
@@ -67,7 +127,9 @@ module ActiveRecord
|
|
|
67
127
|
end
|
|
68
128
|
|
|
69
129
|
# Calls the given block once for each element in row collection, passing
|
|
70
|
-
# row as parameter.
|
|
130
|
+
# row as parameter. Each row is a Hash-like, read only object.
|
|
131
|
+
#
|
|
132
|
+
# To get real hashes, use +.to_a.each+.
|
|
71
133
|
#
|
|
72
134
|
# Returns an +Enumerator+ if no block is given.
|
|
73
135
|
def each(&block)
|
|
@@ -99,6 +161,24 @@ module ActiveRecord
|
|
|
99
161
|
n ? hash_rows.last(n) : hash_rows.last
|
|
100
162
|
end
|
|
101
163
|
|
|
164
|
+
# Returns the +ActiveRecord::Type+ type of all columns.
|
|
165
|
+
# Note that not all database adapters return the result types,
|
|
166
|
+
# so the hash may be empty.
|
|
167
|
+
def column_types
|
|
168
|
+
if @column_types
|
|
169
|
+
@types_hash ||= begin
|
|
170
|
+
types = {}
|
|
171
|
+
@columns.each_with_index do |name, index|
|
|
172
|
+
type = @column_types[index] || Type.default_value
|
|
173
|
+
types[name] = types[index] = type
|
|
174
|
+
end
|
|
175
|
+
types.freeze
|
|
176
|
+
end
|
|
177
|
+
else
|
|
178
|
+
EMPTY_HASH
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
102
182
|
def result # :nodoc:
|
|
103
183
|
self
|
|
104
184
|
end
|
|
@@ -107,7 +187,7 @@ module ActiveRecord
|
|
|
107
187
|
self
|
|
108
188
|
end
|
|
109
189
|
|
|
110
|
-
def cast_values(type_overrides =
|
|
190
|
+
def cast_values(type_overrides = nil) # :nodoc:
|
|
111
191
|
if columns.one?
|
|
112
192
|
# Separated to avoid allocating an array per row
|
|
113
193
|
|
|
@@ -134,14 +214,14 @@ module ActiveRecord
|
|
|
134
214
|
end
|
|
135
215
|
|
|
136
216
|
def initialize_copy(other)
|
|
137
|
-
@
|
|
138
|
-
@rows = rows.dup
|
|
139
|
-
@column_types = column_types.dup
|
|
217
|
+
@rows = rows.dup
|
|
140
218
|
@hash_rows = nil
|
|
141
219
|
end
|
|
142
220
|
|
|
143
221
|
def freeze # :nodoc:
|
|
144
222
|
hash_rows.freeze
|
|
223
|
+
indexed_rows
|
|
224
|
+
column_types
|
|
145
225
|
super
|
|
146
226
|
end
|
|
147
227
|
|
|
@@ -149,21 +229,32 @@ module ActiveRecord
|
|
|
149
229
|
@column_indexes ||= begin
|
|
150
230
|
index = 0
|
|
151
231
|
hash = {}
|
|
152
|
-
length
|
|
232
|
+
length = columns.length
|
|
153
233
|
while index < length
|
|
154
234
|
hash[columns[index]] = index
|
|
155
235
|
index += 1
|
|
156
236
|
end
|
|
157
|
-
hash
|
|
237
|
+
hash.freeze
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def indexed_rows # :nodoc:
|
|
242
|
+
@indexed_rows ||= begin
|
|
243
|
+
columns = column_indexes
|
|
244
|
+
@rows.map { |row| IndexedRow.new(columns, row) }.freeze
|
|
158
245
|
end
|
|
159
246
|
end
|
|
160
247
|
|
|
161
248
|
private
|
|
162
249
|
def column_type(name, index, type_overrides)
|
|
163
|
-
type_overrides
|
|
164
|
-
|
|
165
|
-
|
|
250
|
+
if type_overrides
|
|
251
|
+
type_overrides.fetch(name) do
|
|
252
|
+
column_type(name, index, nil)
|
|
166
253
|
end
|
|
254
|
+
elsif @column_types
|
|
255
|
+
@column_types[index] || Type.default_value
|
|
256
|
+
else
|
|
257
|
+
Type.default_value
|
|
167
258
|
end
|
|
168
259
|
end
|
|
169
260
|
|
|
@@ -175,14 +266,8 @@ module ActiveRecord
|
|
|
175
266
|
end
|
|
176
267
|
end
|
|
177
268
|
|
|
178
|
-
|
|
269
|
+
EMPTY_ARRAY = [].freeze
|
|
179
270
|
EMPTY_HASH = {}.freeze
|
|
180
|
-
private_constant :EMPTY_HASH
|
|
181
|
-
|
|
182
|
-
EMPTY = new(empty_array, empty_array, EMPTY_HASH).freeze
|
|
183
|
-
private_constant :EMPTY
|
|
184
|
-
|
|
185
|
-
EMPTY_ASYNC = FutureResult.wrap(EMPTY).freeze
|
|
186
|
-
private_constant :EMPTY_ASYNC
|
|
271
|
+
private_constant :EMPTY_ARRAY, :EMPTY_HASH
|
|
187
272
|
end
|
|
188
273
|
end
|
|
@@ -3,80 +3,64 @@
|
|
|
3
3
|
module ActiveRecord
|
|
4
4
|
# This is a thread locals registry for Active Record. For example:
|
|
5
5
|
#
|
|
6
|
-
# ActiveRecord::RuntimeRegistry.sql_runtime
|
|
6
|
+
# ActiveRecord::RuntimeRegistry.stats.sql_runtime
|
|
7
7
|
#
|
|
8
8
|
# returns the connection handler local to the current unit of execution (either thread of fiber).
|
|
9
9
|
module RuntimeRegistry # :nodoc:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
class Stats
|
|
11
|
+
attr_accessor :sql_runtime, :async_sql_runtime, :queries_count, :cached_queries_count
|
|
12
|
+
|
|
13
|
+
def initialize
|
|
14
|
+
@sql_runtime = 0.0
|
|
15
|
+
@async_sql_runtime = 0.0
|
|
16
|
+
@queries_count = 0
|
|
17
|
+
@cached_queries_count = 0
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def reset_runtimes
|
|
21
|
+
sql_runtime_was = @sql_runtime
|
|
22
|
+
@sql_runtime = 0.0
|
|
23
|
+
@async_sql_runtime = 0.0
|
|
24
|
+
sql_runtime_was
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
public alias_method :reset, :initialize
|
|
14
28
|
end
|
|
15
29
|
|
|
16
|
-
|
|
17
|
-
ActiveSupport::IsolatedExecutionState[:active_record_sql_runtime] = runtime
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def async_sql_runtime
|
|
21
|
-
ActiveSupport::IsolatedExecutionState[:active_record_async_sql_runtime] ||= 0.0
|
|
22
|
-
end
|
|
30
|
+
extend self
|
|
23
31
|
|
|
24
|
-
def
|
|
25
|
-
|
|
32
|
+
def call(name, start, finish, id, payload)
|
|
33
|
+
record(
|
|
34
|
+
payload[:name],
|
|
35
|
+
(finish - start) * 1_000.0,
|
|
36
|
+
cached: payload[:cached],
|
|
37
|
+
async: payload[:async],
|
|
38
|
+
lock_wait: payload[:lock_wait],
|
|
39
|
+
)
|
|
26
40
|
end
|
|
27
41
|
|
|
28
|
-
def
|
|
29
|
-
|
|
30
|
-
end
|
|
42
|
+
def record(query_name, runtime, cached: false, async: false, lock_wait: nil)
|
|
43
|
+
stats = self.stats
|
|
31
44
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
45
|
+
unless query_name == "TRANSACTION" || query_name == "SCHEMA"
|
|
46
|
+
stats.queries_count += 1
|
|
47
|
+
stats.cached_queries_count += 1 if cached
|
|
48
|
+
end
|
|
35
49
|
|
|
36
|
-
|
|
37
|
-
|
|
50
|
+
if async
|
|
51
|
+
stats.async_sql_runtime += (runtime - lock_wait)
|
|
52
|
+
end
|
|
53
|
+
stats.sql_runtime += runtime
|
|
38
54
|
end
|
|
39
55
|
|
|
40
|
-
def
|
|
41
|
-
ActiveSupport::IsolatedExecutionState[:
|
|
56
|
+
def stats
|
|
57
|
+
ActiveSupport::IsolatedExecutionState[:active_record_runtime] ||= Stats.new
|
|
42
58
|
end
|
|
43
59
|
|
|
44
60
|
def reset
|
|
45
|
-
|
|
46
|
-
reset_queries_count
|
|
47
|
-
reset_cached_queries_count
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def reset_runtimes
|
|
51
|
-
rt, self.sql_runtime = sql_runtime, 0.0
|
|
52
|
-
self.async_sql_runtime = 0.0
|
|
53
|
-
rt
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def reset_queries_count
|
|
57
|
-
qc = queries_count
|
|
58
|
-
self.queries_count = 0
|
|
59
|
-
qc
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def reset_cached_queries_count
|
|
63
|
-
qc = cached_queries_count
|
|
64
|
-
self.cached_queries_count = 0
|
|
65
|
-
qc
|
|
61
|
+
stats.reset
|
|
66
62
|
end
|
|
67
63
|
end
|
|
68
64
|
end
|
|
69
65
|
|
|
70
|
-
ActiveSupport::Notifications.monotonic_subscribe("sql.active_record"
|
|
71
|
-
unless ["SCHEMA", "TRANSACTION"].include?(payload[:name])
|
|
72
|
-
ActiveRecord::RuntimeRegistry.queries_count += 1
|
|
73
|
-
ActiveRecord::RuntimeRegistry.cached_queries_count += 1 if payload[:cached]
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
runtime = (finish - start) * 1_000.0
|
|
77
|
-
|
|
78
|
-
if payload[:async]
|
|
79
|
-
ActiveRecord::RuntimeRegistry.async_sql_runtime += (runtime - payload[:lock_wait])
|
|
80
|
-
end
|
|
81
|
-
ActiveRecord::RuntimeRegistry.sql_runtime += runtime
|
|
82
|
-
end
|
|
66
|
+
ActiveSupport::Notifications.monotonic_subscribe("sql.active_record", ActiveRecord::RuntimeRegistry)
|
|
@@ -105,12 +105,13 @@ module ActiveRecord
|
|
|
105
105
|
# sanitize_sql_hash_for_assignment({ status: nil, group_id: 1 }, "posts")
|
|
106
106
|
# # => "`posts`.`status` = NULL, `posts`.`group_id` = 1"
|
|
107
107
|
def sanitize_sql_hash_for_assignment(attrs, table)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
108
|
+
with_connection do |c|
|
|
109
|
+
attrs.map do |attr, value|
|
|
110
|
+
type = type_for_attribute(attr)
|
|
111
|
+
value = type.serialize(type.cast(value))
|
|
112
|
+
"#{c.quote_table_name_for_assignment(table, attr)} = #{c.quote(value)}"
|
|
113
|
+
end.join(", ")
|
|
114
|
+
end
|
|
114
115
|
end
|
|
115
116
|
|
|
116
117
|
# Sanitizes a +string+ so that it is safe to use within an SQL
|
|
@@ -160,6 +161,8 @@ module ActiveRecord
|
|
|
160
161
|
#
|
|
161
162
|
# sanitize_sql_array(["role = ?", 0])
|
|
162
163
|
# # => "role = '0'"
|
|
164
|
+
#
|
|
165
|
+
# Before using this method, please consider if Arel.sql would be better for your use-case
|
|
163
166
|
def sanitize_sql_array(ary)
|
|
164
167
|
statement, *values = ary
|
|
165
168
|
if values.first.is_a?(Hash) && /:\w+/.match?(statement)
|
|
@@ -63,6 +63,7 @@ module ActiveRecord
|
|
|
63
63
|
extensions(stream)
|
|
64
64
|
types(stream)
|
|
65
65
|
tables(stream)
|
|
66
|
+
virtual_tables(stream)
|
|
66
67
|
trailer(stream)
|
|
67
68
|
stream
|
|
68
69
|
end
|
|
@@ -126,6 +127,10 @@ module ActiveRecord
|
|
|
126
127
|
def schemas(stream)
|
|
127
128
|
end
|
|
128
129
|
|
|
130
|
+
# virtual tables are only supported by SQLite
|
|
131
|
+
def virtual_tables(stream)
|
|
132
|
+
end
|
|
133
|
+
|
|
129
134
|
def tables(stream)
|
|
130
135
|
sorted_tables = @connection.tables.sort
|
|
131
136
|
|
|
@@ -160,7 +165,7 @@ module ActiveRecord
|
|
|
160
165
|
# first dump primary key column
|
|
161
166
|
pk = @connection.primary_key(table)
|
|
162
167
|
|
|
163
|
-
tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
|
|
168
|
+
tbl.print " create_table #{relation_name(remove_prefix_and_suffix(table)).inspect}"
|
|
164
169
|
|
|
165
170
|
case pk
|
|
166
171
|
when String
|
|
@@ -187,7 +192,7 @@ module ActiveRecord
|
|
|
187
192
|
tbl.puts ", force: :cascade do |t|"
|
|
188
193
|
|
|
189
194
|
# then dump all non-primary key columns
|
|
190
|
-
columns.each do |column|
|
|
195
|
+
columns.sort_by(&:name).each do |column|
|
|
191
196
|
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
|
|
192
197
|
next if column.name == pk
|
|
193
198
|
|
|
@@ -202,12 +207,17 @@ module ActiveRecord
|
|
|
202
207
|
end
|
|
203
208
|
|
|
204
209
|
indexes_in_create(table, tbl)
|
|
205
|
-
check_constraints_in_create(table, tbl) if @connection.supports_check_constraints?
|
|
210
|
+
remaining = check_constraints_in_create(table, tbl) if @connection.supports_check_constraints?
|
|
206
211
|
exclusion_constraints_in_create(table, tbl) if @connection.supports_exclusion_constraints?
|
|
207
212
|
unique_constraints_in_create(table, tbl) if @connection.supports_unique_constraints?
|
|
208
213
|
|
|
209
214
|
tbl.puts " end"
|
|
210
215
|
|
|
216
|
+
if remaining
|
|
217
|
+
tbl.puts
|
|
218
|
+
tbl.print remaining.string
|
|
219
|
+
end
|
|
220
|
+
|
|
211
221
|
stream.print tbl.string
|
|
212
222
|
rescue => e
|
|
213
223
|
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
|
|
@@ -222,8 +232,8 @@ module ActiveRecord
|
|
|
222
232
|
def indexes(table, stream)
|
|
223
233
|
if (indexes = @connection.indexes(table)).any?
|
|
224
234
|
add_index_statements = indexes.map do |index|
|
|
225
|
-
table_name = remove_prefix_and_suffix(index.table)
|
|
226
|
-
" add_index #{([table_name] + index_parts(index)).join(', ')}"
|
|
235
|
+
table_name = remove_prefix_and_suffix(index.table)
|
|
236
|
+
" add_index #{([relation_name(table_name).inspect] + index_parts(index)).join(', ')}"
|
|
227
237
|
end
|
|
228
238
|
|
|
229
239
|
stream.puts add_index_statements.sort.join("\n")
|
|
@@ -267,35 +277,49 @@ module ActiveRecord
|
|
|
267
277
|
index_parts << "nulls_not_distinct: #{index.nulls_not_distinct.inspect}" if index.nulls_not_distinct
|
|
268
278
|
index_parts << "type: #{index.type.inspect}" if index.type
|
|
269
279
|
index_parts << "comment: #{index.comment.inspect}" if index.comment
|
|
280
|
+
index_parts << "enabled: #{index.enabled.inspect}" if @connection.supports_disabling_indexes? && index.disabled?
|
|
270
281
|
index_parts
|
|
271
282
|
end
|
|
272
283
|
|
|
273
284
|
def check_constraints_in_create(table, stream)
|
|
274
285
|
if (check_constraints = @connection.check_constraints(table)).any?
|
|
275
|
-
|
|
276
|
-
parts = [
|
|
277
|
-
"t.check_constraint #{check_constraint.expression.inspect}"
|
|
278
|
-
]
|
|
286
|
+
check_valid, check_invalid = check_constraints.partition { |chk| chk.validate? }
|
|
279
287
|
|
|
280
|
-
|
|
281
|
-
|
|
288
|
+
unless check_valid.empty?
|
|
289
|
+
check_constraint_statements = check_valid.map do |check|
|
|
290
|
+
" t.check_constraint #{check_parts(check).join(', ')}"
|
|
282
291
|
end
|
|
283
292
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
" #{parts.join(', ')}"
|
|
293
|
+
stream.puts check_constraint_statements.sort.join("\n")
|
|
287
294
|
end
|
|
288
295
|
|
|
289
|
-
|
|
296
|
+
unless check_invalid.empty?
|
|
297
|
+
remaining = StringIO.new
|
|
298
|
+
table_name = remove_prefix_and_suffix(table).inspect
|
|
299
|
+
|
|
300
|
+
add_check_constraint_statements = check_invalid.map do |check|
|
|
301
|
+
" add_check_constraint #{([table_name] + check_parts(check)).join(', ')}"
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
remaining.puts add_check_constraint_statements.sort.join("\n")
|
|
305
|
+
remaining
|
|
306
|
+
end
|
|
290
307
|
end
|
|
291
308
|
end
|
|
292
309
|
|
|
310
|
+
def check_parts(check)
|
|
311
|
+
check_parts = [ check.expression.inspect ]
|
|
312
|
+
check_parts << "name: #{check.name.inspect}" if check.export_name_on_schema_dump?
|
|
313
|
+
check_parts << "validate: #{check.validate?.inspect}" unless check.validate?
|
|
314
|
+
check_parts
|
|
315
|
+
end
|
|
316
|
+
|
|
293
317
|
def foreign_keys(table, stream)
|
|
294
318
|
if (foreign_keys = @connection.foreign_keys(table)).any?
|
|
295
319
|
add_foreign_key_statements = foreign_keys.map do |foreign_key|
|
|
296
320
|
parts = [
|
|
297
|
-
|
|
298
|
-
remove_prefix_and_suffix(foreign_key.to_table).inspect,
|
|
321
|
+
relation_name(remove_prefix_and_suffix(foreign_key.from_table)).inspect,
|
|
322
|
+
relation_name(remove_prefix_and_suffix(foreign_key.to_table)).inspect,
|
|
299
323
|
]
|
|
300
324
|
|
|
301
325
|
if foreign_key.column != @connection.foreign_key_column_for(foreign_key.to_table, "id")
|
|
@@ -306,16 +330,13 @@ module ActiveRecord
|
|
|
306
330
|
parts << "primary_key: #{foreign_key.primary_key.inspect}"
|
|
307
331
|
end
|
|
308
332
|
|
|
309
|
-
if foreign_key.export_name_on_schema_dump?
|
|
310
|
-
parts << "name: #{foreign_key.name.inspect}"
|
|
311
|
-
end
|
|
312
|
-
|
|
333
|
+
parts << "name: #{foreign_key.name.inspect}" if foreign_key.export_name_on_schema_dump?
|
|
313
334
|
parts << "on_update: #{foreign_key.on_update.inspect}" if foreign_key.on_update
|
|
314
335
|
parts << "on_delete: #{foreign_key.on_delete.inspect}" if foreign_key.on_delete
|
|
315
336
|
parts << "deferrable: #{foreign_key.deferrable.inspect}" if foreign_key.deferrable
|
|
316
337
|
parts << "validate: #{foreign_key.validate?.inspect}" unless foreign_key.validate?
|
|
317
338
|
|
|
318
|
-
" #{parts.join(', ')}"
|
|
339
|
+
" add_foreign_key #{parts.join(', ')}"
|
|
319
340
|
end
|
|
320
341
|
|
|
321
342
|
stream.puts add_foreign_key_statements.sort.join("\n")
|
|
@@ -340,6 +361,10 @@ module ActiveRecord
|
|
|
340
361
|
end
|
|
341
362
|
end
|
|
342
363
|
|
|
364
|
+
def relation_name(name)
|
|
365
|
+
name
|
|
366
|
+
end
|
|
367
|
+
|
|
343
368
|
def remove_prefix_and_suffix(table)
|
|
344
369
|
# This method appears at the top when profiling active_record test cases run.
|
|
345
370
|
# Avoid costly calculation when there are no prefix and suffix.
|
|
@@ -34,7 +34,8 @@ module ActiveRecord
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def delete_all_versions
|
|
37
|
-
|
|
37
|
+
# Eagerly check in connection to avoid checking in/out many times in the called method.
|
|
38
|
+
@pool.with_connection do
|
|
38
39
|
versions.each do |version|
|
|
39
40
|
delete_version(version)
|
|
40
41
|
end
|
|
@@ -23,7 +23,7 @@ module ActiveRecord
|
|
|
23
23
|
scope = current_scope
|
|
24
24
|
|
|
25
25
|
if scope
|
|
26
|
-
if self == scope.
|
|
26
|
+
if self == scope.model
|
|
27
27
|
scope.clone
|
|
28
28
|
else
|
|
29
29
|
relation.merge!(scope)
|
|
@@ -191,7 +191,10 @@ module ActiveRecord
|
|
|
191
191
|
private
|
|
192
192
|
def singleton_method_added(name)
|
|
193
193
|
super
|
|
194
|
-
|
|
194
|
+
# Most Kernel extends are both singleton and instance methods so
|
|
195
|
+
# respond_to is a fast check, but we don't want to define methods
|
|
196
|
+
# only on the module (ex. Module#name)
|
|
197
|
+
generate_relation_method(name) if Kernel.respond_to?(name) && (Kernel.method_defined?(name) || Kernel.private_method_defined?(name)) && !ActiveRecord::Relation.method_defined?(name)
|
|
195
198
|
end
|
|
196
199
|
end
|
|
197
200
|
end
|
|
@@ -30,13 +30,13 @@ module ActiveRecord
|
|
|
30
30
|
# {validates_uniqueness_of}[rdoc-ref:Validations::ClassMethods#validates_uniqueness_of] can.
|
|
31
31
|
# You're encouraged to add a unique index in the database to deal with this even more unlikely scenario.
|
|
32
32
|
#
|
|
33
|
-
#
|
|
33
|
+
# ==== Options
|
|
34
34
|
#
|
|
35
|
-
# [
|
|
35
|
+
# [+:length+]
|
|
36
36
|
# Length of the Secure Random, with a minimum of 24 characters. It will
|
|
37
37
|
# default to 24.
|
|
38
38
|
#
|
|
39
|
-
# [
|
|
39
|
+
# [+:on+]
|
|
40
40
|
# The callback when the value is generated. When called with <tt>on:
|
|
41
41
|
# :initialize</tt>, the value is generated in an
|
|
42
42
|
# <tt>after_initialize</tt> callback, otherwise the value will be used
|