activerecord 7.0.8.7 → 7.1.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 +1339 -1572
- data/MIT-LICENSE +1 -1
- data/README.rdoc +15 -16
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +18 -3
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +16 -11
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency.rb +10 -8
- data/lib/active_record/associations/preloader/association.rb +27 -6
- data/lib/active_record/associations/preloader.rb +12 -9
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +193 -97
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +40 -26
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +18 -5
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +105 -21
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +55 -9
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +10 -24
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +63 -43
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +109 -32
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +60 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +289 -122
- data/lib/active_record/connection_adapters/abstract/transaction.rb +280 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +502 -91
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +200 -108
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -143
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -12
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -29
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +9 -6
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +351 -54
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +336 -168
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +42 -36
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +4 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -7
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +162 -77
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +71 -94
- data/lib/active_record/core.rb +128 -138
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +22 -12
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +8 -3
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +2 -0
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +36 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +17 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -54
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +2 -2
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +19 -22
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +113 -26
- data/lib/active_record/errors.rb +89 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +119 -71
- data/lib/active_record/future_result.rb +30 -5
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +55 -8
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +118 -30
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +5 -7
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +100 -4
- data/lib/active_record/migration/compatibility.rb +131 -5
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration.rb +213 -109
- data/lib/active_record/model_schema.rb +47 -27
- data/lib/active_record/nested_attributes.rb +28 -3
- data/lib/active_record/normalization.rb +158 -0
- data/lib/active_record/persistence.rb +183 -33
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +77 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +107 -45
- data/lib/active_record/railties/controller_runtime.rb +10 -5
- data/lib/active_record/railties/databases.rake +139 -145
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +169 -45
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +152 -63
- data/lib/active_record/relation/delegation.rb +22 -8
- data/lib/active_record/relation/finder_methods.rb +85 -15
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -2
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +26 -14
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +351 -62
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +76 -35
- data/lib/active_record/result.rb +19 -5
- data/lib/active_record/runtime_registry.rb +10 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +41 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +7 -5
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +10 -1
- data/lib/active_record/tasks/database_tasks.rb +127 -105
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -7
- data/lib/active_record/test_fixtures.rb +113 -96
- data/lib/active_record/timestamp.rb +26 -14
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +36 -10
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +121 -16
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +0 -8
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +81 -17
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +52 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -4,8 +4,234 @@ require "active_support/core_ext/file/atomic"
|
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
6
|
module ConnectionAdapters
|
7
|
+
class SchemaReflection
|
8
|
+
class << self
|
9
|
+
attr_accessor :use_schema_cache_dump
|
10
|
+
attr_accessor :check_schema_cache_dump_version
|
11
|
+
end
|
12
|
+
|
13
|
+
self.use_schema_cache_dump = true
|
14
|
+
self.check_schema_cache_dump_version = true
|
15
|
+
|
16
|
+
def initialize(cache_path, cache = nil)
|
17
|
+
@cache = cache
|
18
|
+
@cache_path = cache_path
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_schema_cache(cache)
|
22
|
+
@cache = cache
|
23
|
+
end
|
24
|
+
|
25
|
+
def clear!
|
26
|
+
@cache = empty_cache
|
27
|
+
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def load!(connection)
|
32
|
+
cache(connection)
|
33
|
+
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def primary_keys(connection, table_name)
|
38
|
+
cache(connection).primary_keys(connection, table_name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def data_source_exists?(connection, name)
|
42
|
+
cache(connection).data_source_exists?(connection, name)
|
43
|
+
end
|
44
|
+
|
45
|
+
def add(connection, name)
|
46
|
+
cache(connection).add(connection, name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def data_sources(connection, name)
|
50
|
+
cache(connection).data_sources(connection, name)
|
51
|
+
end
|
52
|
+
|
53
|
+
def columns(connection, table_name)
|
54
|
+
cache(connection).columns(connection, table_name)
|
55
|
+
end
|
56
|
+
|
57
|
+
def columns_hash(connection, table_name)
|
58
|
+
cache(connection).columns_hash(connection, table_name)
|
59
|
+
end
|
60
|
+
|
61
|
+
def columns_hash?(connection, table_name)
|
62
|
+
cache(connection).columns_hash?(connection, table_name)
|
63
|
+
end
|
64
|
+
|
65
|
+
def indexes(connection, table_name)
|
66
|
+
cache(connection).indexes(connection, table_name)
|
67
|
+
end
|
68
|
+
|
69
|
+
def database_version(connection)
|
70
|
+
cache(connection).database_version(connection)
|
71
|
+
end
|
72
|
+
|
73
|
+
def version(connection)
|
74
|
+
cache(connection).version(connection)
|
75
|
+
end
|
76
|
+
|
77
|
+
def size(connection)
|
78
|
+
cache(connection).size
|
79
|
+
end
|
80
|
+
|
81
|
+
def clear_data_source_cache!(connection, name)
|
82
|
+
return if @cache.nil? && !possible_cache_available?
|
83
|
+
|
84
|
+
cache(connection).clear_data_source_cache!(connection, name)
|
85
|
+
end
|
86
|
+
|
87
|
+
def cached?(table_name)
|
88
|
+
if @cache.nil?
|
89
|
+
# If `check_schema_cache_dump_version` is enabled we can't load
|
90
|
+
# the schema cache dump without connecting to the database.
|
91
|
+
unless self.class.check_schema_cache_dump_version
|
92
|
+
@cache = load_cache(nil)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
@cache&.cached?(table_name)
|
97
|
+
end
|
98
|
+
|
99
|
+
def dump_to(connection, filename)
|
100
|
+
fresh_cache = empty_cache
|
101
|
+
fresh_cache.add_all(connection)
|
102
|
+
fresh_cache.dump_to(filename)
|
103
|
+
|
104
|
+
@cache = fresh_cache
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
def empty_cache
|
109
|
+
new_cache = SchemaCache.allocate
|
110
|
+
new_cache.send(:initialize)
|
111
|
+
new_cache
|
112
|
+
end
|
113
|
+
|
114
|
+
def cache(connection)
|
115
|
+
@cache ||= load_cache(connection) || empty_cache
|
116
|
+
end
|
117
|
+
|
118
|
+
def possible_cache_available?
|
119
|
+
self.class.use_schema_cache_dump &&
|
120
|
+
@cache_path &&
|
121
|
+
File.file?(@cache_path)
|
122
|
+
end
|
123
|
+
|
124
|
+
def load_cache(connection)
|
125
|
+
# Can't load if schema dumps are disabled
|
126
|
+
return unless possible_cache_available?
|
127
|
+
|
128
|
+
# Check we can find one
|
129
|
+
return unless new_cache = SchemaCache._load_from(@cache_path)
|
130
|
+
|
131
|
+
if self.class.check_schema_cache_dump_version
|
132
|
+
begin
|
133
|
+
current_version = connection.schema_version
|
134
|
+
|
135
|
+
if new_cache.version(connection) != current_version
|
136
|
+
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}."
|
137
|
+
return
|
138
|
+
end
|
139
|
+
rescue ActiveRecordError => error
|
140
|
+
warn "Failed to validate the schema cache because of #{error.class}: #{error.message}"
|
141
|
+
return
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
new_cache
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class BoundSchemaReflection
|
150
|
+
def initialize(abstract_schema_reflection, connection)
|
151
|
+
@schema_reflection = abstract_schema_reflection
|
152
|
+
@connection = connection
|
153
|
+
end
|
154
|
+
|
155
|
+
def clear!
|
156
|
+
@schema_reflection.clear!
|
157
|
+
end
|
158
|
+
|
159
|
+
def load!
|
160
|
+
@schema_reflection.load!(@connection)
|
161
|
+
end
|
162
|
+
|
163
|
+
def cached?(table_name)
|
164
|
+
@schema_reflection.cached?(table_name)
|
165
|
+
end
|
166
|
+
|
167
|
+
def primary_keys(table_name)
|
168
|
+
@schema_reflection.primary_keys(@connection, table_name)
|
169
|
+
end
|
170
|
+
|
171
|
+
def data_source_exists?(name)
|
172
|
+
@schema_reflection.data_source_exists?(@connection, name)
|
173
|
+
end
|
174
|
+
|
175
|
+
def add(name)
|
176
|
+
@schema_reflection.add(@connection, name)
|
177
|
+
end
|
178
|
+
|
179
|
+
def data_sources(name)
|
180
|
+
@schema_reflection.data_sources(@connection, name)
|
181
|
+
end
|
182
|
+
|
183
|
+
def columns(table_name)
|
184
|
+
@schema_reflection.columns(@connection, table_name)
|
185
|
+
end
|
186
|
+
|
187
|
+
def columns_hash(table_name)
|
188
|
+
@schema_reflection.columns_hash(@connection, table_name)
|
189
|
+
end
|
190
|
+
|
191
|
+
def columns_hash?(table_name)
|
192
|
+
@schema_reflection.columns_hash?(@connection, table_name)
|
193
|
+
end
|
194
|
+
|
195
|
+
def indexes(table_name)
|
196
|
+
@schema_reflection.indexes(@connection, table_name)
|
197
|
+
end
|
198
|
+
|
199
|
+
def database_version
|
200
|
+
@schema_reflection.database_version(@connection)
|
201
|
+
end
|
202
|
+
|
203
|
+
def version
|
204
|
+
@schema_reflection.version(@connection)
|
205
|
+
end
|
206
|
+
|
207
|
+
def size
|
208
|
+
@schema_reflection.size(@connection)
|
209
|
+
end
|
210
|
+
|
211
|
+
def clear_data_source_cache!(name)
|
212
|
+
@schema_reflection.clear_data_source_cache!(@connection, name)
|
213
|
+
end
|
214
|
+
|
215
|
+
def dump_to(filename)
|
216
|
+
@schema_reflection.dump_to(@connection, filename)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# = Active Record Connection Adapters Schema Cache
|
7
221
|
class SchemaCache
|
8
|
-
|
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
|
+
def self._load_from(filename) # :nodoc:
|
9
235
|
return unless File.file?(filename)
|
10
236
|
|
11
237
|
read(filename) do |file|
|
@@ -32,20 +258,17 @@ module ActiveRecord
|
|
32
258
|
end
|
33
259
|
private_class_method :read
|
34
260
|
|
35
|
-
|
36
|
-
attr_accessor :connection
|
37
|
-
|
38
|
-
def initialize(conn)
|
39
|
-
@connection = conn
|
40
|
-
|
261
|
+
def initialize
|
41
262
|
@columns = {}
|
42
263
|
@columns_hash = {}
|
43
264
|
@primary_keys = {}
|
44
265
|
@data_sources = {}
|
45
266
|
@indexes = {}
|
267
|
+
@database_version = nil
|
268
|
+
@version = nil
|
46
269
|
end
|
47
270
|
|
48
|
-
def initialize_dup(other)
|
271
|
+
def initialize_dup(other) # :nodoc:
|
49
272
|
super
|
50
273
|
@columns = @columns.dup
|
51
274
|
@columns_hash = @columns_hash.dup
|
@@ -54,61 +277,67 @@ module ActiveRecord
|
|
54
277
|
@indexes = @indexes.dup
|
55
278
|
end
|
56
279
|
|
57
|
-
def encode_with(coder)
|
58
|
-
|
59
|
-
|
60
|
-
coder["
|
61
|
-
coder["
|
62
|
-
coder["data_sources"] = @data_sources
|
63
|
-
coder["indexes"] = @indexes
|
280
|
+
def encode_with(coder) # :nodoc:
|
281
|
+
coder["columns"] = @columns.sort.to_h
|
282
|
+
coder["primary_keys"] = @primary_keys.sort.to_h
|
283
|
+
coder["data_sources"] = @data_sources.sort.to_h
|
284
|
+
coder["indexes"] = @indexes.sort.to_h
|
64
285
|
coder["version"] = @version
|
65
|
-
coder["database_version"] = database_version
|
286
|
+
coder["database_version"] = @database_version
|
66
287
|
end
|
67
288
|
|
68
289
|
def init_with(coder)
|
69
290
|
@columns = coder["columns"]
|
291
|
+
@columns_hash = coder["columns_hash"]
|
70
292
|
@primary_keys = coder["primary_keys"]
|
71
293
|
@data_sources = coder["data_sources"]
|
72
294
|
@indexes = coder["indexes"] || {}
|
73
295
|
@version = coder["version"]
|
74
296
|
@database_version = coder["database_version"]
|
75
297
|
|
76
|
-
|
298
|
+
unless coder["deduplicated"]
|
299
|
+
derive_columns_hash_and_deduplicate_values
|
300
|
+
end
|
77
301
|
end
|
78
302
|
|
79
|
-
def
|
303
|
+
def cached?(table_name)
|
304
|
+
@columns.key?(table_name)
|
305
|
+
end
|
306
|
+
|
307
|
+
def primary_keys(connection, table_name)
|
80
308
|
@primary_keys.fetch(table_name) do
|
81
|
-
if data_source_exists?(table_name)
|
309
|
+
if data_source_exists?(connection, table_name)
|
82
310
|
@primary_keys[deep_deduplicate(table_name)] = deep_deduplicate(connection.primary_key(table_name))
|
83
311
|
end
|
84
312
|
end
|
85
313
|
end
|
86
314
|
|
87
315
|
# A cached lookup for table existence.
|
88
|
-
def data_source_exists?(name)
|
316
|
+
def data_source_exists?(connection, name)
|
89
317
|
return if ignored_table?(name)
|
90
|
-
prepare_data_sources if @data_sources.empty?
|
318
|
+
prepare_data_sources(connection) if @data_sources.empty?
|
91
319
|
return @data_sources[name] if @data_sources.key? name
|
92
320
|
|
93
321
|
@data_sources[deep_deduplicate(name)] = connection.data_source_exists?(name)
|
94
322
|
end
|
95
323
|
|
96
324
|
# Add internal cache for table with +table_name+.
|
97
|
-
def add(table_name)
|
98
|
-
if data_source_exists?(table_name)
|
99
|
-
primary_keys(table_name)
|
100
|
-
columns(table_name)
|
101
|
-
columns_hash(table_name)
|
102
|
-
indexes(table_name)
|
325
|
+
def add(connection, table_name)
|
326
|
+
if data_source_exists?(connection, table_name)
|
327
|
+
primary_keys(connection, table_name)
|
328
|
+
columns(connection, table_name)
|
329
|
+
columns_hash(connection, table_name)
|
330
|
+
indexes(connection, table_name)
|
103
331
|
end
|
104
332
|
end
|
105
333
|
|
106
|
-
def data_sources(name)
|
334
|
+
def data_sources(_connection, name) # :nodoc:
|
107
335
|
@data_sources[name]
|
108
336
|
end
|
337
|
+
deprecate data_sources: :data_source_exists?, deprecator: ActiveRecord.deprecator
|
109
338
|
|
110
339
|
# Get the columns for a table
|
111
|
-
def columns(table_name)
|
340
|
+
def columns(connection, table_name)
|
112
341
|
if ignored_table?(table_name)
|
113
342
|
raise ActiveRecord::StatementInvalid, "Table '#{table_name}' doesn't exist"
|
114
343
|
end
|
@@ -120,20 +349,20 @@ module ActiveRecord
|
|
120
349
|
|
121
350
|
# Get the columns for a table as a hash, key is the column name
|
122
351
|
# value is the column object.
|
123
|
-
def columns_hash(table_name)
|
352
|
+
def columns_hash(connection, table_name)
|
124
353
|
@columns_hash.fetch(table_name) do
|
125
|
-
@columns_hash[deep_deduplicate(table_name)] = columns(table_name).index_by(&:name).freeze
|
354
|
+
@columns_hash[deep_deduplicate(table_name)] = columns(connection, table_name).index_by(&:name).freeze
|
126
355
|
end
|
127
356
|
end
|
128
357
|
|
129
358
|
# Checks whether the columns hash is already cached for a table.
|
130
|
-
def columns_hash?(table_name)
|
359
|
+
def columns_hash?(connection, table_name)
|
131
360
|
@columns_hash.key?(table_name)
|
132
361
|
end
|
133
362
|
|
134
|
-
def indexes(table_name)
|
363
|
+
def indexes(connection, table_name)
|
135
364
|
@indexes.fetch(table_name) do
|
136
|
-
if data_source_exists?(table_name)
|
365
|
+
if data_source_exists?(connection, table_name)
|
137
366
|
@indexes[deep_deduplicate(table_name)] = deep_deduplicate(connection.indexes(table_name))
|
138
367
|
else
|
139
368
|
[]
|
@@ -141,19 +370,16 @@ module ActiveRecord
|
|
141
370
|
end
|
142
371
|
end
|
143
372
|
|
144
|
-
def database_version # :nodoc:
|
373
|
+
def database_version(connection) # :nodoc:
|
145
374
|
@database_version ||= connection.get_database_version
|
146
375
|
end
|
147
376
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
@
|
154
|
-
@indexes.clear
|
155
|
-
@version = nil
|
156
|
-
@database_version = nil
|
377
|
+
def version(connection)
|
378
|
+
@version ||= connection.schema_version
|
379
|
+
end
|
380
|
+
|
381
|
+
def schema_version
|
382
|
+
@version
|
157
383
|
end
|
158
384
|
|
159
385
|
def size
|
@@ -161,7 +387,7 @@ module ActiveRecord
|
|
161
387
|
end
|
162
388
|
|
163
389
|
# Clear out internal caches for the data source +name+.
|
164
|
-
def clear_data_source_cache!(name)
|
390
|
+
def clear_data_source_cache!(_connection, name)
|
165
391
|
@columns.delete name
|
166
392
|
@columns_hash.delete name
|
167
393
|
@primary_keys.delete name
|
@@ -169,9 +395,16 @@ module ActiveRecord
|
|
169
395
|
@indexes.delete name
|
170
396
|
end
|
171
397
|
|
398
|
+
def add_all(connection) # :nodoc:
|
399
|
+
tables_to_cache(connection).each do |table|
|
400
|
+
add(connection, table)
|
401
|
+
end
|
402
|
+
|
403
|
+
version(connection)
|
404
|
+
database_version(connection)
|
405
|
+
end
|
406
|
+
|
172
407
|
def dump_to(filename)
|
173
|
-
clear!
|
174
|
-
tables_to_cache.each { |table| add(table) }
|
175
408
|
open(filename) { |f|
|
176
409
|
if filename.include?(".dump")
|
177
410
|
f.write(Marshal.dump(self))
|
@@ -181,13 +414,11 @@ module ActiveRecord
|
|
181
414
|
}
|
182
415
|
end
|
183
416
|
|
184
|
-
def marshal_dump
|
185
|
-
|
186
|
-
|
187
|
-
[@version, @columns, {}, @primary_keys, @data_sources, @indexes, database_version]
|
417
|
+
def marshal_dump # :nodoc:
|
418
|
+
[@version, @columns, {}, @primary_keys, @data_sources, @indexes, @database_version]
|
188
419
|
end
|
189
420
|
|
190
|
-
def marshal_load(array)
|
421
|
+
def marshal_load(array) # :nodoc:
|
191
422
|
@version, @columns, _columns_hash, @primary_keys, @data_sources, @indexes, @database_version = array
|
192
423
|
@indexes ||= {}
|
193
424
|
|
@@ -195,7 +426,7 @@ module ActiveRecord
|
|
195
426
|
end
|
196
427
|
|
197
428
|
private
|
198
|
-
def tables_to_cache
|
429
|
+
def tables_to_cache(connection)
|
199
430
|
connection.data_sources.reject do |table|
|
200
431
|
ignored_table?(table)
|
201
432
|
end
|
@@ -207,10 +438,6 @@ module ActiveRecord
|
|
207
438
|
end
|
208
439
|
end
|
209
440
|
|
210
|
-
def reset_version!
|
211
|
-
@version = connection.schema_version
|
212
|
-
end
|
213
|
-
|
214
441
|
def derive_columns_hash_and_deduplicate_values
|
215
442
|
@columns = deep_deduplicate(@columns)
|
216
443
|
@columns_hash = @columns.transform_values { |columns| columns.index_by(&:name) }
|
@@ -232,8 +459,8 @@ module ActiveRecord
|
|
232
459
|
end
|
233
460
|
end
|
234
461
|
|
235
|
-
def prepare_data_sources
|
236
|
-
tables_to_cache.each do |source|
|
462
|
+
def prepare_data_sources(connection)
|
463
|
+
tables_to_cache(connection).each do |source|
|
237
464
|
@data_sources[source] = true
|
238
465
|
end
|
239
466
|
end
|
@@ -244,6 +471,7 @@ module ActiveRecord
|
|
244
471
|
File.atomic_write(filename) do |file|
|
245
472
|
if File.extname(filename) == ".gz"
|
246
473
|
zipper = Zlib::GzipWriter.new file
|
474
|
+
zipper.mtime = 0
|
247
475
|
yield zipper
|
248
476
|
zipper.flush
|
249
477
|
zipper.close
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module SQLite3
|
6
|
+
class Column < ConnectionAdapters::Column # :nodoc:
|
7
|
+
attr_reader :rowid
|
8
|
+
|
9
|
+
def initialize(*, auto_increment: nil, rowid: false, **)
|
10
|
+
super
|
11
|
+
@auto_increment = auto_increment
|
12
|
+
@rowid = rowid
|
13
|
+
end
|
14
|
+
|
15
|
+
def auto_increment?
|
16
|
+
@auto_increment
|
17
|
+
end
|
18
|
+
|
19
|
+
def auto_incremented_by_db?
|
20
|
+
auto_increment? || rowid
|
21
|
+
end
|
22
|
+
|
23
|
+
def init_with(coder)
|
24
|
+
@auto_increment = coder["auto_increment"]
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
def encode_with(coder)
|
29
|
+
coder["auto_increment"] = @auto_increment
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
def ==(other)
|
34
|
+
other.is_a?(Column) &&
|
35
|
+
super &&
|
36
|
+
auto_increment? == other.auto_increment?
|
37
|
+
end
|
38
|
+
alias :eql? :==
|
39
|
+
|
40
|
+
def hash
|
41
|
+
Column.hash ^
|
42
|
+
super.hash ^
|
43
|
+
auto_increment?.hash ^
|
44
|
+
rowid.hash
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -15,39 +15,25 @@ module ActiveRecord
|
|
15
15
|
!READ_QUERY.match?(sql.b)
|
16
16
|
end
|
17
17
|
|
18
|
-
def explain(arel, binds = [])
|
19
|
-
sql
|
20
|
-
|
18
|
+
def explain(arel, binds = [], _options = [])
|
19
|
+
sql = "EXPLAIN QUERY PLAN " + to_sql(arel, binds)
|
20
|
+
result = internal_exec_query(sql, "EXPLAIN", [])
|
21
|
+
SQLite3::ExplainPrettyPrinter.new.pp(result)
|
21
22
|
end
|
22
23
|
|
23
|
-
def
|
24
|
+
def internal_exec_query(sql, name = nil, binds = [], prepare: false, async: false) # :nodoc:
|
24
25
|
sql = transform_query(sql)
|
25
26
|
check_if_write_query(sql)
|
26
27
|
|
27
|
-
materialize_transactions
|
28
|
-
mark_transaction_written_if_write(sql)
|
29
|
-
|
30
|
-
log(sql, name) do
|
31
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
32
|
-
@connection.execute(sql)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def exec_query(sql, name = nil, binds = [], prepare: false, async: false) # :nodoc:
|
38
|
-
sql = transform_query(sql)
|
39
|
-
check_if_write_query(sql)
|
40
|
-
|
41
|
-
materialize_transactions
|
42
28
|
mark_transaction_written_if_write(sql)
|
43
29
|
|
44
30
|
type_casted_binds = type_casted_binds(binds)
|
45
31
|
|
46
32
|
log(sql, name, binds, type_casted_binds, async: async) do
|
47
|
-
|
33
|
+
with_raw_connection do |conn|
|
48
34
|
# Don't cache statements if they are not prepared
|
49
35
|
unless prepare
|
50
|
-
stmt =
|
36
|
+
stmt = conn.prepare(sql)
|
51
37
|
begin
|
52
38
|
cols = stmt.columns
|
53
39
|
unless without_prepared_statement?(binds)
|
@@ -58,7 +44,7 @@ module ActiveRecord
|
|
58
44
|
stmt.close
|
59
45
|
end
|
60
46
|
else
|
61
|
-
stmt = @statements[sql] ||=
|
47
|
+
stmt = @statements[sql] ||= conn.prepare(sql)
|
62
48
|
cols = stmt.columns
|
63
49
|
stmt.reset!
|
64
50
|
stmt.bind_params(type_casted_binds)
|
@@ -71,8 +57,8 @@ module ActiveRecord
|
|
71
57
|
end
|
72
58
|
|
73
59
|
def exec_delete(sql, name = "SQL", binds = []) # :nodoc:
|
74
|
-
|
75
|
-
@
|
60
|
+
internal_exec_query(sql, name, binds)
|
61
|
+
@raw_connection.changes
|
76
62
|
end
|
77
63
|
alias :exec_update :exec_delete
|
78
64
|
|
@@ -80,22 +66,36 @@ module ActiveRecord
|
|
80
66
|
raise TransactionIsolationError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted
|
81
67
|
raise StandardError, "You need to enable the shared-cache mode in SQLite mode before attempting to change the transaction isolation level" unless shared_cache?
|
82
68
|
|
83
|
-
|
84
|
-
|
85
|
-
|
69
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
70
|
+
ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted] = conn.get_first_value("PRAGMA read_uncommitted")
|
71
|
+
conn.read_uncommitted = true
|
72
|
+
begin_db_transaction
|
73
|
+
end
|
86
74
|
end
|
87
75
|
|
88
76
|
def begin_db_transaction # :nodoc:
|
89
|
-
log("begin transaction", "TRANSACTION")
|
77
|
+
log("begin transaction", "TRANSACTION") do
|
78
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
79
|
+
conn.transaction
|
80
|
+
end
|
81
|
+
end
|
90
82
|
end
|
91
83
|
|
92
84
|
def commit_db_transaction # :nodoc:
|
93
|
-
log("commit transaction", "TRANSACTION")
|
85
|
+
log("commit transaction", "TRANSACTION") do
|
86
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
87
|
+
conn.commit
|
88
|
+
end
|
89
|
+
end
|
94
90
|
reset_read_uncommitted
|
95
91
|
end
|
96
92
|
|
97
93
|
def exec_rollback_db_transaction # :nodoc:
|
98
|
-
log("rollback transaction", "TRANSACTION")
|
94
|
+
log("rollback transaction", "TRANSACTION") do
|
95
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
96
|
+
conn.rollback
|
97
|
+
end
|
98
|
+
end
|
99
99
|
reset_read_uncommitted
|
100
100
|
end
|
101
101
|
|
@@ -109,11 +109,19 @@ module ActiveRecord
|
|
109
109
|
end
|
110
110
|
|
111
111
|
private
|
112
|
+
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: false)
|
113
|
+
log(sql, name, async: async) do
|
114
|
+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
115
|
+
conn.execute(sql)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
112
120
|
def reset_read_uncommitted
|
113
121
|
read_uncommitted = ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted]
|
114
122
|
return unless read_uncommitted
|
115
123
|
|
116
|
-
@
|
124
|
+
@raw_connection&.read_uncommitted = read_uncommitted
|
117
125
|
end
|
118
126
|
|
119
127
|
def execute_batch(statements, name = nil)
|
@@ -121,19 +129,17 @@ module ActiveRecord
|
|
121
129
|
sql = combine_multi_statements(statements)
|
122
130
|
|
123
131
|
check_if_write_query(sql)
|
124
|
-
|
125
|
-
materialize_transactions
|
126
132
|
mark_transaction_written_if_write(sql)
|
127
133
|
|
128
134
|
log(sql, name) do
|
129
|
-
|
130
|
-
|
135
|
+
with_raw_connection do |conn|
|
136
|
+
conn.execute_batch2(sql)
|
131
137
|
end
|
132
138
|
end
|
133
139
|
end
|
134
140
|
|
135
141
|
def last_inserted_id(result)
|
136
|
-
@
|
142
|
+
@raw_connection.last_insert_row_id
|
137
143
|
end
|
138
144
|
|
139
145
|
def build_fixture_statements(fixture_set)
|