activerecord 7.1.5.1 → 7.2.0.beta1
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 +515 -2445
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +9 -8
- data/lib/active_record/associations/belongs_to_association.rb +14 -7
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/collection_association.rb +6 -4
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +29 -28
- data/lib/active_record/associations/join_dependency.rb +5 -5
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +2 -1
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +33 -16
- data/lib/active_record/attribute_assignment.rb +1 -11
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +1 -1
- data/lib/active_record/attribute_methods/primary_key.rb +23 -55
- data/lib/active_record/attribute_methods/read.rb +4 -16
- data/lib/active_record/attribute_methods/serialization.rb +4 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -10
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +60 -71
- data/lib/active_record/attributes.rb +55 -42
- data/lib/active_record/autosave_association.rb +13 -32
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +248 -65
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +34 -17
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +159 -74
- data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/transaction.rb +60 -57
- data/lib/active_record/connection_adapters/abstract_adapter.rb +18 -46
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +32 -6
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -1
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +11 -5
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +5 -23
- data/lib/active_record/connection_adapters/pool_config.rb +7 -6
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -13
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +26 -21
- data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +44 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +25 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +107 -75
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +12 -6
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -48
- data/lib/active_record/connection_adapters.rb +121 -0
- data/lib/active_record/connection_handling.rb +56 -41
- data/lib/active_record/core.rb +53 -37
- data/lib/active_record/counter_cache.rb +18 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
- data/lib/active_record/database_configurations/database_config.rb +15 -4
- data/lib/active_record/database_configurations/hash_config.rb +38 -34
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +24 -0
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/encryptable_record.rb +2 -2
- data/lib/active_record/encryption/encrypted_attribute_type.rb +22 -2
- data/lib/active_record/encryption/encryptor.rb +17 -2
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption.rb +0 -2
- data/lib/active_record/enum.rb +10 -1
- data/lib/active_record/errors.rb +16 -11
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -31
- data/lib/active_record/future_result.rb +8 -4
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +18 -15
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +7 -6
- data/lib/active_record/log_subscriber.rb +0 -21
- data/lib/active_record/marshalling.rb +1 -4
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +2 -3
- data/lib/active_record/migration/compatibility.rb +5 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +85 -76
- data/lib/active_record/model_schema.rb +28 -68
- data/lib/active_record/nested_attributes.rb +13 -16
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +30 -352
- data/lib/active_record/query_cache.rb +18 -6
- data/lib/active_record/query_logs.rb +15 -0
- data/lib/active_record/querying.rb +21 -9
- data/lib/active_record/railtie.rb +50 -62
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +41 -44
- data/lib/active_record/reflection.rb +90 -35
- data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +94 -61
- data/lib/active_record/relation/delegation.rb +8 -11
- data/lib/active_record/relation/finder_methods.rb +16 -2
- data/lib/active_record/relation/merger.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder.rb +3 -3
- data/lib/active_record/relation/query_methods.rb +196 -57
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +2 -18
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +496 -72
- data/lib/active_record/result.rb +31 -44
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +24 -19
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +19 -9
- data/lib/active_record/schema_migration.rb +30 -14
- data/lib/active_record/signed_id.rb +11 -1
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/table_metadata.rb +1 -10
- data/lib/active_record/tasks/database_tasks.rb +76 -70
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
- data/lib/active_record/test_fixtures.rb +81 -91
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +1 -1
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +68 -0
- data/lib/active_record/transactions.rb +43 -14
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +14 -10
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +149 -40
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/nodes/binary.rb +0 -6
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +4 -3
- data/lib/arel/nodes/sql_literal.rb +7 -0
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/to_sql.rb +29 -16
- data/lib/arel.rb +7 -3
- metadata +20 -15
@@ -18,70 +18,62 @@ module ActiveRecord
|
|
18
18
|
@cache_path = cache_path
|
19
19
|
end
|
20
20
|
|
21
|
-
def set_schema_cache(cache)
|
22
|
-
@cache = cache
|
23
|
-
end
|
24
|
-
|
25
21
|
def clear!
|
26
22
|
@cache = empty_cache
|
27
23
|
|
28
24
|
nil
|
29
25
|
end
|
30
26
|
|
31
|
-
def load!(
|
32
|
-
cache(
|
27
|
+
def load!(pool)
|
28
|
+
cache(pool)
|
33
29
|
|
34
30
|
self
|
35
31
|
end
|
36
32
|
|
37
|
-
def primary_keys(
|
38
|
-
cache(
|
33
|
+
def primary_keys(pool, table_name)
|
34
|
+
cache(pool).primary_keys(pool, table_name)
|
39
35
|
end
|
40
36
|
|
41
|
-
def data_source_exists?(
|
42
|
-
cache(
|
37
|
+
def data_source_exists?(pool, name)
|
38
|
+
cache(pool).data_source_exists?(pool, name)
|
43
39
|
end
|
44
40
|
|
45
|
-
def add(
|
46
|
-
cache(
|
41
|
+
def add(pool, name)
|
42
|
+
cache(pool).add(pool, name)
|
47
43
|
end
|
48
44
|
|
49
|
-
def data_sources(
|
50
|
-
cache(
|
45
|
+
def data_sources(pool, name)
|
46
|
+
cache(pool).data_source_exists?(pool, name)
|
51
47
|
end
|
52
48
|
|
53
|
-
def columns(
|
54
|
-
cache(
|
49
|
+
def columns(pool, table_name)
|
50
|
+
cache(pool).columns(pool, table_name)
|
55
51
|
end
|
56
52
|
|
57
|
-
def columns_hash(
|
58
|
-
cache(
|
53
|
+
def columns_hash(pool, table_name)
|
54
|
+
cache(pool).columns_hash(pool, table_name)
|
59
55
|
end
|
60
56
|
|
61
|
-
def columns_hash?(
|
62
|
-
cache(
|
57
|
+
def columns_hash?(pool, table_name)
|
58
|
+
cache(pool).columns_hash?(pool, table_name)
|
63
59
|
end
|
64
60
|
|
65
|
-
def indexes(
|
66
|
-
cache(
|
61
|
+
def indexes(pool, table_name)
|
62
|
+
cache(pool).indexes(pool, table_name)
|
67
63
|
end
|
68
64
|
|
69
|
-
def
|
70
|
-
cache(
|
65
|
+
def version(pool)
|
66
|
+
cache(pool).version(pool)
|
71
67
|
end
|
72
68
|
|
73
|
-
def
|
74
|
-
cache(
|
69
|
+
def size(pool)
|
70
|
+
cache(pool).size
|
75
71
|
end
|
76
72
|
|
77
|
-
def
|
78
|
-
cache(connection).size
|
79
|
-
end
|
80
|
-
|
81
|
-
def clear_data_source_cache!(connection, name)
|
73
|
+
def clear_data_source_cache!(pool, name)
|
82
74
|
return if @cache.nil? && !possible_cache_available?
|
83
75
|
|
84
|
-
cache(
|
76
|
+
cache(pool).clear_data_source_cache!(pool, name)
|
85
77
|
end
|
86
78
|
|
87
79
|
def cached?(table_name)
|
@@ -96,9 +88,9 @@ module ActiveRecord
|
|
96
88
|
@cache&.cached?(table_name)
|
97
89
|
end
|
98
90
|
|
99
|
-
def dump_to(
|
91
|
+
def dump_to(pool, filename)
|
100
92
|
fresh_cache = empty_cache
|
101
|
-
fresh_cache.add_all(
|
93
|
+
fresh_cache.add_all(pool)
|
102
94
|
fresh_cache.dump_to(filename)
|
103
95
|
|
104
96
|
@cache = fresh_cache
|
@@ -111,8 +103,8 @@ module ActiveRecord
|
|
111
103
|
new_cache
|
112
104
|
end
|
113
105
|
|
114
|
-
def cache(
|
115
|
-
@cache ||= load_cache(
|
106
|
+
def cache(pool)
|
107
|
+
@cache ||= load_cache(pool) || empty_cache
|
116
108
|
end
|
117
109
|
|
118
110
|
def possible_cache_available?
|
@@ -121,7 +113,7 @@ module ActiveRecord
|
|
121
113
|
File.file?(@cache_path)
|
122
114
|
end
|
123
115
|
|
124
|
-
def load_cache(
|
116
|
+
def load_cache(pool)
|
125
117
|
# Can't load if schema dumps are disabled
|
126
118
|
return unless possible_cache_available?
|
127
119
|
|
@@ -130,11 +122,13 @@ module ActiveRecord
|
|
130
122
|
|
131
123
|
if self.class.check_schema_cache_dump_version
|
132
124
|
begin
|
133
|
-
|
125
|
+
pool.with_connection do |connection|
|
126
|
+
current_version = connection.schema_version
|
134
127
|
|
135
|
-
|
136
|
-
|
137
|
-
|
128
|
+
if new_cache.version(connection) != current_version
|
129
|
+
warn "Ignoring #{@cache_path} because it has expired. The current schema version is #{current_version}, but the one in the schema cache file is #{new_cache.schema_version}."
|
130
|
+
return
|
131
|
+
end
|
138
132
|
end
|
139
133
|
rescue ActiveRecordError => error
|
140
134
|
warn "Failed to validate the schema cache because of #{error.class}: #{error.message}"
|
@@ -147,9 +141,25 @@ module ActiveRecord
|
|
147
141
|
end
|
148
142
|
|
149
143
|
class BoundSchemaReflection
|
150
|
-
|
144
|
+
class FakePool # :nodoc
|
145
|
+
def initialize(connection)
|
146
|
+
@connection = connection
|
147
|
+
end
|
148
|
+
|
149
|
+
def with_connection
|
150
|
+
yield @connection
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
class << self
|
155
|
+
def for_lone_connection(abstract_schema_reflection, connection) # :nodoc:
|
156
|
+
new(abstract_schema_reflection, FakePool.new(connection))
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def initialize(abstract_schema_reflection, pool)
|
151
161
|
@schema_reflection = abstract_schema_reflection
|
152
|
-
@
|
162
|
+
@pool = pool
|
153
163
|
end
|
154
164
|
|
155
165
|
def clear!
|
@@ -157,7 +167,7 @@ module ActiveRecord
|
|
157
167
|
end
|
158
168
|
|
159
169
|
def load!
|
160
|
-
@schema_reflection.load!(@
|
170
|
+
@schema_reflection.load!(@pool)
|
161
171
|
end
|
162
172
|
|
163
173
|
def cached?(table_name)
|
@@ -165,72 +175,56 @@ module ActiveRecord
|
|
165
175
|
end
|
166
176
|
|
167
177
|
def primary_keys(table_name)
|
168
|
-
@schema_reflection.primary_keys(@
|
178
|
+
@schema_reflection.primary_keys(@pool, table_name)
|
169
179
|
end
|
170
180
|
|
171
181
|
def data_source_exists?(name)
|
172
|
-
@schema_reflection.data_source_exists?(@
|
182
|
+
@schema_reflection.data_source_exists?(@pool, name)
|
173
183
|
end
|
174
184
|
|
175
185
|
def add(name)
|
176
|
-
@schema_reflection.add(@
|
186
|
+
@schema_reflection.add(@pool, name)
|
177
187
|
end
|
178
188
|
|
179
189
|
def data_sources(name)
|
180
|
-
@schema_reflection.data_sources(@
|
190
|
+
@schema_reflection.data_sources(@pool, name)
|
181
191
|
end
|
182
192
|
|
183
193
|
def columns(table_name)
|
184
|
-
@schema_reflection.columns(@
|
194
|
+
@schema_reflection.columns(@pool, table_name)
|
185
195
|
end
|
186
196
|
|
187
197
|
def columns_hash(table_name)
|
188
|
-
@schema_reflection.columns_hash(@
|
198
|
+
@schema_reflection.columns_hash(@pool, table_name)
|
189
199
|
end
|
190
200
|
|
191
201
|
def columns_hash?(table_name)
|
192
|
-
@schema_reflection.columns_hash?(@
|
202
|
+
@schema_reflection.columns_hash?(@pool, table_name)
|
193
203
|
end
|
194
204
|
|
195
205
|
def indexes(table_name)
|
196
|
-
@schema_reflection.indexes(@
|
197
|
-
end
|
198
|
-
|
199
|
-
def database_version # :nodoc:
|
200
|
-
@schema_reflection.database_version(@connection)
|
206
|
+
@schema_reflection.indexes(@pool, table_name)
|
201
207
|
end
|
202
208
|
|
203
209
|
def version
|
204
|
-
@schema_reflection.version(@
|
210
|
+
@schema_reflection.version(@pool)
|
205
211
|
end
|
206
212
|
|
207
213
|
def size
|
208
|
-
@schema_reflection.size(@
|
214
|
+
@schema_reflection.size(@pool)
|
209
215
|
end
|
210
216
|
|
211
217
|
def clear_data_source_cache!(name)
|
212
|
-
@schema_reflection.clear_data_source_cache!(@
|
218
|
+
@schema_reflection.clear_data_source_cache!(@pool, name)
|
213
219
|
end
|
214
220
|
|
215
221
|
def dump_to(filename)
|
216
|
-
@schema_reflection.dump_to(@
|
222
|
+
@schema_reflection.dump_to(@pool, filename)
|
217
223
|
end
|
218
224
|
end
|
219
225
|
|
220
226
|
# = Active Record Connection Adapters Schema Cache
|
221
227
|
class SchemaCache
|
222
|
-
class << self
|
223
|
-
def new(connection)
|
224
|
-
BoundSchemaReflection.new(SchemaReflection.new(nil), connection)
|
225
|
-
end
|
226
|
-
deprecate new: "use ActiveRecord::ConnectionAdapters::SchemaReflection instead", deprecator: ActiveRecord.deprecator
|
227
|
-
|
228
|
-
def load_from(filename) # :nodoc:
|
229
|
-
BoundSchemaReflection.new(SchemaReflection.new(filename), nil)
|
230
|
-
end
|
231
|
-
deprecate load_from: "use ActiveRecord::ConnectionAdapters::SchemaReflection instead", deprecator: ActiveRecord.deprecator
|
232
|
-
end
|
233
|
-
|
234
228
|
def self._load_from(filename) # :nodoc:
|
235
229
|
return unless File.file?(filename)
|
236
230
|
|
@@ -258,13 +252,12 @@ module ActiveRecord
|
|
258
252
|
end
|
259
253
|
private_class_method :read
|
260
254
|
|
261
|
-
def initialize
|
255
|
+
def initialize # :nodoc:
|
262
256
|
@columns = {}
|
263
257
|
@columns_hash = {}
|
264
258
|
@primary_keys = {}
|
265
259
|
@data_sources = {}
|
266
260
|
@indexes = {}
|
267
|
-
@database_version = nil
|
268
261
|
@version = nil
|
269
262
|
end
|
270
263
|
|
@@ -283,17 +276,15 @@ module ActiveRecord
|
|
283
276
|
coder["data_sources"] = @data_sources.sort.to_h
|
284
277
|
coder["indexes"] = @indexes.sort.to_h
|
285
278
|
coder["version"] = @version
|
286
|
-
coder["database_version"] = @database_version
|
287
279
|
end
|
288
280
|
|
289
|
-
def init_with(coder)
|
281
|
+
def init_with(coder) # :nodoc:
|
290
282
|
@columns = coder["columns"]
|
291
283
|
@columns_hash = coder["columns_hash"]
|
292
284
|
@primary_keys = coder["primary_keys"]
|
293
285
|
@data_sources = coder["data_sources"]
|
294
286
|
@indexes = coder["indexes"] || {}
|
295
287
|
@version = coder["version"]
|
296
|
-
@database_version = coder["database_version"]
|
297
288
|
|
298
289
|
unless coder["deduplicated"]
|
299
290
|
derive_columns_hash_and_deduplicate_values
|
@@ -304,78 +295,85 @@ module ActiveRecord
|
|
304
295
|
@columns.key?(table_name)
|
305
296
|
end
|
306
297
|
|
307
|
-
def primary_keys(
|
298
|
+
def primary_keys(pool, table_name)
|
308
299
|
@primary_keys.fetch(table_name) do
|
309
|
-
|
310
|
-
|
300
|
+
pool.with_connection do |connection|
|
301
|
+
if data_source_exists?(pool, table_name)
|
302
|
+
@primary_keys[deep_deduplicate(table_name)] = deep_deduplicate(connection.primary_key(table_name))
|
303
|
+
end
|
311
304
|
end
|
312
305
|
end
|
313
306
|
end
|
314
307
|
|
315
308
|
# A cached lookup for table existence.
|
316
|
-
def data_source_exists?(
|
309
|
+
def data_source_exists?(pool, name)
|
317
310
|
return if ignored_table?(name)
|
318
|
-
|
311
|
+
|
312
|
+
if @data_sources.empty?
|
313
|
+
tables_to_cache(pool).each do |source|
|
314
|
+
@data_sources[source] = true
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
319
318
|
return @data_sources[name] if @data_sources.key? name
|
320
319
|
|
321
|
-
@data_sources[deep_deduplicate(name)] = connection
|
320
|
+
@data_sources[deep_deduplicate(name)] = pool.with_connection do |connection|
|
321
|
+
connection.data_source_exists?(name)
|
322
|
+
end
|
322
323
|
end
|
323
324
|
|
324
325
|
# Add internal cache for table with +table_name+.
|
325
|
-
def add(
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
326
|
+
def add(pool, table_name)
|
327
|
+
pool.with_connection do
|
328
|
+
if data_source_exists?(pool, table_name)
|
329
|
+
primary_keys(pool, table_name)
|
330
|
+
columns(pool, table_name)
|
331
|
+
columns_hash(pool, table_name)
|
332
|
+
indexes(pool, table_name)
|
333
|
+
end
|
331
334
|
end
|
332
335
|
end
|
333
336
|
|
334
|
-
def data_sources(_connection, name) # :nodoc:
|
335
|
-
@data_sources[name]
|
336
|
-
end
|
337
|
-
deprecate data_sources: :data_source_exists?, deprecator: ActiveRecord.deprecator
|
338
|
-
|
339
337
|
# Get the columns for a table
|
340
|
-
def columns(
|
338
|
+
def columns(pool, table_name)
|
341
339
|
if ignored_table?(table_name)
|
342
|
-
raise ActiveRecord::StatementInvalid
|
340
|
+
raise ActiveRecord::StatementInvalid.new("Table '#{table_name}' doesn't exist", connection_pool: pool)
|
343
341
|
end
|
344
342
|
|
345
343
|
@columns.fetch(table_name) do
|
346
|
-
|
344
|
+
pool.with_connection do |connection|
|
345
|
+
@columns[deep_deduplicate(table_name)] = deep_deduplicate(connection.columns(table_name))
|
346
|
+
end
|
347
347
|
end
|
348
348
|
end
|
349
349
|
|
350
350
|
# Get the columns for a table as a hash, key is the column name
|
351
351
|
# value is the column object.
|
352
|
-
def columns_hash(
|
352
|
+
def columns_hash(pool, table_name)
|
353
353
|
@columns_hash.fetch(table_name) do
|
354
|
-
@columns_hash[deep_deduplicate(table_name)] = columns(
|
354
|
+
@columns_hash[deep_deduplicate(table_name)] = columns(pool, table_name).index_by(&:name).freeze
|
355
355
|
end
|
356
356
|
end
|
357
357
|
|
358
358
|
# Checks whether the columns hash is already cached for a table.
|
359
|
-
def columns_hash?(
|
359
|
+
def columns_hash?(_pool, table_name)
|
360
360
|
@columns_hash.key?(table_name)
|
361
361
|
end
|
362
362
|
|
363
|
-
def indexes(
|
363
|
+
def indexes(pool, table_name)
|
364
364
|
@indexes.fetch(table_name) do
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
365
|
+
pool.with_connection do |connection|
|
366
|
+
if data_source_exists?(pool, table_name)
|
367
|
+
@indexes[deep_deduplicate(table_name)] = deep_deduplicate(connection.indexes(table_name))
|
368
|
+
else
|
369
|
+
[]
|
370
|
+
end
|
369
371
|
end
|
370
372
|
end
|
371
373
|
end
|
372
374
|
|
373
|
-
def
|
374
|
-
@
|
375
|
-
end
|
376
|
-
|
377
|
-
def version(connection)
|
378
|
-
@version ||= connection.schema_version
|
375
|
+
def version(pool)
|
376
|
+
@version ||= pool.with_connection(&:schema_version)
|
379
377
|
end
|
380
378
|
|
381
379
|
def schema_version
|
@@ -395,13 +393,14 @@ module ActiveRecord
|
|
395
393
|
@indexes.delete name
|
396
394
|
end
|
397
395
|
|
398
|
-
def add_all(
|
399
|
-
|
400
|
-
|
401
|
-
|
396
|
+
def add_all(pool) # :nodoc:
|
397
|
+
pool.with_connection do
|
398
|
+
tables_to_cache(pool).each do |table|
|
399
|
+
add(pool, table)
|
400
|
+
end
|
402
401
|
|
403
|
-
|
404
|
-
|
402
|
+
version(pool)
|
403
|
+
end
|
405
404
|
end
|
406
405
|
|
407
406
|
def dump_to(filename)
|
@@ -415,20 +414,22 @@ module ActiveRecord
|
|
415
414
|
end
|
416
415
|
|
417
416
|
def marshal_dump # :nodoc:
|
418
|
-
[@version, @columns, {}, @primary_keys, @data_sources, @indexes
|
417
|
+
[@version, @columns, {}, @primary_keys, @data_sources, @indexes]
|
419
418
|
end
|
420
419
|
|
421
420
|
def marshal_load(array) # :nodoc:
|
422
|
-
@version, @columns, _columns_hash, @primary_keys, @data_sources, @indexes,
|
421
|
+
@version, @columns, _columns_hash, @primary_keys, @data_sources, @indexes, _database_version = array
|
423
422
|
@indexes ||= {}
|
424
423
|
|
425
424
|
derive_columns_hash_and_deduplicate_values
|
426
425
|
end
|
427
426
|
|
428
427
|
private
|
429
|
-
def tables_to_cache(
|
430
|
-
|
431
|
-
|
428
|
+
def tables_to_cache(pool)
|
429
|
+
pool.with_connection do |connection|
|
430
|
+
connection.data_sources.reject do |table|
|
431
|
+
ignored_table?(table)
|
432
|
+
end
|
432
433
|
end
|
433
434
|
end
|
434
435
|
|
@@ -459,12 +460,6 @@ module ActiveRecord
|
|
459
460
|
end
|
460
461
|
end
|
461
462
|
|
462
|
-
def prepare_data_sources(connection)
|
463
|
-
tables_to_cache(connection).each do |source|
|
464
|
-
@data_sources[source] = true
|
465
|
-
end
|
466
|
-
end
|
467
|
-
|
468
463
|
def open(filename)
|
469
464
|
FileUtils.mkdir_p(File.dirname(filename))
|
470
465
|
|
@@ -6,10 +6,11 @@ module ActiveRecord
|
|
6
6
|
class Column < ConnectionAdapters::Column # :nodoc:
|
7
7
|
attr_reader :rowid
|
8
8
|
|
9
|
-
def initialize(*, auto_increment: nil, rowid: false, **)
|
9
|
+
def initialize(*, auto_increment: nil, rowid: false, generated_type: nil, **)
|
10
10
|
super
|
11
11
|
@auto_increment = auto_increment
|
12
12
|
@rowid = rowid
|
13
|
+
@generated_type = generated_type
|
13
14
|
end
|
14
15
|
|
15
16
|
def auto_increment?
|
@@ -20,6 +21,18 @@ module ActiveRecord
|
|
20
21
|
auto_increment? || rowid
|
21
22
|
end
|
22
23
|
|
24
|
+
def virtual?
|
25
|
+
!@generated_type.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
def virtual_stored?
|
29
|
+
virtual? && @generated_type == :stored
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_default?
|
33
|
+
super && !virtual?
|
34
|
+
end
|
35
|
+
|
23
36
|
def init_with(coder)
|
24
37
|
@auto_increment = coder["auto_increment"]
|
25
38
|
super
|
@@ -21,7 +21,7 @@ module ActiveRecord
|
|
21
21
|
SQLite3::ExplainPrettyPrinter.new.pp(result)
|
22
22
|
end
|
23
23
|
|
24
|
-
def internal_exec_query(sql, name = nil, binds = [], prepare: false, async: false) # :nodoc:
|
24
|
+
def internal_exec_query(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false) # :nodoc:
|
25
25
|
sql = transform_query(sql)
|
26
26
|
check_if_write_query(sql)
|
27
27
|
|
@@ -29,7 +29,7 @@ module ActiveRecord
|
|
29
29
|
|
30
30
|
type_casted_binds = type_casted_binds(binds)
|
31
31
|
|
32
|
-
log(sql, name, binds, type_casted_binds, async: async) do
|
32
|
+
log(sql, name, binds, type_casted_binds, async: async) do |notification_payload|
|
33
33
|
with_raw_connection do |conn|
|
34
34
|
# Don't cache statements if they are not prepared
|
35
35
|
unless prepare
|
@@ -52,7 +52,9 @@ module ActiveRecord
|
|
52
52
|
end
|
53
53
|
verified!
|
54
54
|
|
55
|
-
build_result(columns: cols, rows: records)
|
55
|
+
result = build_result(columns: cols, rows: records)
|
56
|
+
notification_payload[:row_count] = result.length
|
57
|
+
result
|
56
58
|
end
|
57
59
|
end
|
58
60
|
end
|
@@ -104,7 +106,7 @@ module ActiveRecord
|
|
104
106
|
|
105
107
|
# https://stackoverflow.com/questions/17574784
|
106
108
|
# https://www.sqlite.org/lang_datefunc.html
|
107
|
-
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')").freeze # :nodoc:
|
109
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')", retryable: true).freeze # :nodoc:
|
108
110
|
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
109
111
|
|
110
112
|
def high_precision_current_timestamp
|
@@ -113,10 +115,11 @@ module ActiveRecord
|
|
113
115
|
|
114
116
|
private
|
115
117
|
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: false)
|
116
|
-
log(sql, name, async: async) do
|
118
|
+
log(sql, name, async: async) do |notification_payload|
|
117
119
|
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
118
120
|
result = conn.execute(sql)
|
119
121
|
verified!
|
122
|
+
notification_payload[:row_count] = result.length
|
120
123
|
result
|
121
124
|
end
|
122
125
|
end
|
@@ -136,10 +139,11 @@ module ActiveRecord
|
|
136
139
|
check_if_write_query(sql)
|
137
140
|
mark_transaction_written_if_write(sql)
|
138
141
|
|
139
|
-
log(sql, name) do
|
142
|
+
log(sql, name) do |notification_payload|
|
140
143
|
with_raw_connection do |conn|
|
141
144
|
result = conn.execute_batch2(sql)
|
142
145
|
verified!
|
146
|
+
notification_payload[:row_count] = result.length
|
143
147
|
result
|
144
148
|
end
|
145
149
|
end
|
@@ -4,9 +4,52 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module SQLite3
|
6
6
|
module Quoting # :nodoc:
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
7
9
|
QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
|
8
10
|
QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
|
9
11
|
|
12
|
+
module ClassMethods # :nodoc:
|
13
|
+
def column_name_matcher
|
14
|
+
/
|
15
|
+
\A
|
16
|
+
(
|
17
|
+
(?:
|
18
|
+
# "table_name"."column_name" | function(one or no argument)
|
19
|
+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
|
20
|
+
)
|
21
|
+
(?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
|
22
|
+
)
|
23
|
+
(?:\s*,\s*\g<1>)*
|
24
|
+
\z
|
25
|
+
/ix
|
26
|
+
end
|
27
|
+
|
28
|
+
def column_name_with_order_matcher
|
29
|
+
/
|
30
|
+
\A
|
31
|
+
(
|
32
|
+
(?:
|
33
|
+
# "table_name"."column_name" | function(one or no argument)
|
34
|
+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
|
35
|
+
)
|
36
|
+
(?:\s+COLLATE\s+(?:\w+|"\w+"))?
|
37
|
+
(?:\s+ASC|\s+DESC)?
|
38
|
+
)
|
39
|
+
(?:\s*,\s*\g<1>)*
|
40
|
+
\z
|
41
|
+
/ix
|
42
|
+
end
|
43
|
+
|
44
|
+
def quote_column_name(name)
|
45
|
+
QUOTED_COLUMN_NAMES[name] ||= %Q("#{name.to_s.gsub('"', '""')}").freeze
|
46
|
+
end
|
47
|
+
|
48
|
+
def quote_table_name(name)
|
49
|
+
QUOTED_TABLE_NAMES[name] ||= %Q("#{name.to_s.gsub('"', '""').gsub(".", "\".\"")}").freeze
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
10
53
|
def quote_string(s)
|
11
54
|
::SQLite3::Database.quote(s)
|
12
55
|
end
|
@@ -15,14 +58,6 @@ module ActiveRecord
|
|
15
58
|
quote_column_name(attr)
|
16
59
|
end
|
17
60
|
|
18
|
-
def quote_table_name(name)
|
19
|
-
QUOTED_TABLE_NAMES[name] ||= super.gsub(".", "\".\"").freeze
|
20
|
-
end
|
21
|
-
|
22
|
-
def quote_column_name(name)
|
23
|
-
QUOTED_COLUMN_NAMES[name] ||= %Q("#{super.gsub('"', '""')}")
|
24
|
-
end
|
25
|
-
|
26
61
|
def quoted_time(value)
|
27
62
|
value = value.change(year: 2000, month: 1, day: 1)
|
28
63
|
quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, "2000-01-01 ")
|
@@ -63,7 +98,7 @@ module ActiveRecord
|
|
63
98
|
|
64
99
|
def type_cast(value) # :nodoc:
|
65
100
|
case value
|
66
|
-
when BigDecimal
|
101
|
+
when BigDecimal, Rational
|
67
102
|
value.to_f
|
68
103
|
when String
|
69
104
|
if value.encoding == Encoding::ASCII_8BIT
|
@@ -75,43 +110,6 @@ module ActiveRecord
|
|
75
110
|
super
|
76
111
|
end
|
77
112
|
end
|
78
|
-
|
79
|
-
def column_name_matcher
|
80
|
-
COLUMN_NAME
|
81
|
-
end
|
82
|
-
|
83
|
-
def column_name_with_order_matcher
|
84
|
-
COLUMN_NAME_WITH_ORDER
|
85
|
-
end
|
86
|
-
|
87
|
-
COLUMN_NAME = /
|
88
|
-
\A
|
89
|
-
(
|
90
|
-
(?:
|
91
|
-
# "table_name"."column_name" | function(one or no argument)
|
92
|
-
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
|
93
|
-
)
|
94
|
-
(?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
|
95
|
-
)
|
96
|
-
(?:\s*,\s*\g<1>)*
|
97
|
-
\z
|
98
|
-
/ix
|
99
|
-
|
100
|
-
COLUMN_NAME_WITH_ORDER = /
|
101
|
-
\A
|
102
|
-
(
|
103
|
-
(?:
|
104
|
-
# "table_name"."column_name" | function(one or no argument)
|
105
|
-
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
|
106
|
-
)
|
107
|
-
(?:\s+COLLATE\s+(?:\w+|"\w+"))?
|
108
|
-
(?:\s+ASC|\s+DESC)?
|
109
|
-
)
|
110
|
-
(?:\s*,\s*\g<1>)*
|
111
|
-
\z
|
112
|
-
/ix
|
113
|
-
|
114
|
-
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
115
113
|
end
|
116
114
|
end
|
117
115
|
end
|