activerecord 6.1.7.6 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1055 -1180
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +33 -17
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +15 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +18 -19
- data/lib/active_record/associations/collection_proxy.rb +8 -3
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +6 -2
- data/lib/active_record/associations/preloader/association.rb +186 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +49 -13
- data/lib/active_record/associations/preloader.rb +39 -113
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +90 -82
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +49 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +7 -5
- data/lib/active_record/attribute_methods/serialization.rb +66 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +13 -14
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +6 -21
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/yaml_column.rb +2 -14
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +43 -82
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +34 -13
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +69 -18
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +97 -81
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +35 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +35 -21
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +50 -76
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +27 -16
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -107
- data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +15 -16
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +47 -53
- data/lib/active_record/core.rb +121 -146
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -9
- data/lib/active_record/database_configurations/hash_config.rb +63 -5
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +15 -32
- data/lib/active_record/delegated_type.rb +52 -11
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +61 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +208 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +90 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +49 -42
- data/lib/active_record/errors.rb +67 -4
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +41 -6
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +17 -20
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +80 -14
- data/lib/active_record/integration.rb +4 -3
- data/lib/active_record/internal_metadata.rb +1 -5
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/locking/pessimistic.rb +9 -3
- data/lib/active_record/log_subscriber.rb +14 -3
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +8 -3
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +89 -10
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +110 -80
- data/lib/active_record/model_schema.rb +45 -58
- data/lib/active_record/nested_attributes.rb +13 -12
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +219 -52
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +138 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +127 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +66 -129
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +67 -50
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +40 -36
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +31 -35
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +235 -63
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +169 -84
- data/lib/active_record/result.rb +17 -7
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +10 -3
- data/lib/active_record/schema_migration.rb +4 -4
- data/lib/active_record/scoping/default.rb +61 -12
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/store.rb +1 -6
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +116 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -12
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +9 -13
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +2 -2
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +1 -1
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +1 -1
- data/lib/active_record.rb +204 -28
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +11 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +8 -2
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +58 -2
- data/lib/arel.rb +2 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +58 -14
@@ -31,6 +31,7 @@ module ActiveRecord
|
|
31
31
|
string: { name: "varchar", limit: 255 },
|
32
32
|
text: { name: "text" },
|
33
33
|
integer: { name: "int", limit: 4 },
|
34
|
+
bigint: { name: "bigint" },
|
34
35
|
float: { name: "float", limit: 24 },
|
35
36
|
decimal: { name: "decimal" },
|
36
37
|
datetime: { name: "datetime" },
|
@@ -54,7 +55,7 @@ module ActiveRecord
|
|
54
55
|
super(connection, logger, config)
|
55
56
|
end
|
56
57
|
|
57
|
-
def get_database_version
|
58
|
+
def get_database_version # :nodoc:
|
58
59
|
full_version_string = get_full_version
|
59
60
|
version_string = version_string(full_version_string)
|
60
61
|
Version.new(version_string, full_version_string)
|
@@ -137,6 +138,11 @@ module ActiveRecord
|
|
137
138
|
true
|
138
139
|
end
|
139
140
|
|
141
|
+
def field_ordered_value(column, values) # :nodoc:
|
142
|
+
field = Arel::Nodes::NamedFunction.new("FIELD", [column, values.reverse])
|
143
|
+
Arel::Nodes::Descending.new(field)
|
144
|
+
end
|
145
|
+
|
140
146
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
141
147
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
142
148
|
end
|
@@ -174,7 +180,7 @@ module ActiveRecord
|
|
174
180
|
|
175
181
|
# REFERENTIAL INTEGRITY ====================================
|
176
182
|
|
177
|
-
def disable_referential_integrity
|
183
|
+
def disable_referential_integrity # :nodoc:
|
178
184
|
old = query_value("SELECT @@FOREIGN_KEY_CHECKS")
|
179
185
|
|
180
186
|
begin
|
@@ -185,54 +191,40 @@ module ActiveRecord
|
|
185
191
|
end
|
186
192
|
end
|
187
193
|
|
188
|
-
# CONNECTION MANAGEMENT ====================================
|
189
|
-
|
190
|
-
def clear_cache! # :nodoc:
|
191
|
-
reload_type_map
|
192
|
-
super
|
193
|
-
end
|
194
|
-
|
195
194
|
#--
|
196
195
|
# DATABASE STATEMENTS ======================================
|
197
196
|
#++
|
198
197
|
|
199
198
|
# Executes the SQL statement in the context of this connection.
|
200
|
-
def execute(sql, name = nil)
|
201
|
-
|
202
|
-
mark_transaction_written_if_write(sql)
|
203
|
-
|
204
|
-
log(sql, name) do
|
205
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
206
|
-
@connection.query(sql)
|
207
|
-
end
|
208
|
-
end
|
199
|
+
def execute(sql, name = nil, async: false)
|
200
|
+
raw_execute(sql, name, async)
|
209
201
|
end
|
210
202
|
|
211
203
|
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
212
204
|
# to write stuff in an abstract way without concerning ourselves about whether it
|
213
205
|
# needs to be explicitly freed or not.
|
214
|
-
def execute_and_free(sql, name = nil) # :nodoc:
|
215
|
-
yield execute(sql, name)
|
206
|
+
def execute_and_free(sql, name = nil, async: false) # :nodoc:
|
207
|
+
yield execute(sql, name, async: async)
|
216
208
|
end
|
217
209
|
|
218
|
-
def begin_db_transaction
|
210
|
+
def begin_db_transaction # :nodoc:
|
219
211
|
execute("BEGIN", "TRANSACTION")
|
220
212
|
end
|
221
213
|
|
222
|
-
def begin_isolated_db_transaction(isolation)
|
214
|
+
def begin_isolated_db_transaction(isolation) # :nodoc:
|
223
215
|
execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
|
224
216
|
begin_db_transaction
|
225
217
|
end
|
226
218
|
|
227
|
-
def commit_db_transaction
|
219
|
+
def commit_db_transaction # :nodoc:
|
228
220
|
execute("COMMIT", "TRANSACTION")
|
229
221
|
end
|
230
222
|
|
231
|
-
def exec_rollback_db_transaction
|
223
|
+
def exec_rollback_db_transaction # :nodoc:
|
232
224
|
execute("ROLLBACK", "TRANSACTION")
|
233
225
|
end
|
234
226
|
|
235
|
-
def empty_insert_statement_value(primary_key = nil)
|
227
|
+
def empty_insert_statement_value(primary_key = nil) # :nodoc:
|
236
228
|
"VALUES ()"
|
237
229
|
end
|
238
230
|
|
@@ -270,7 +262,7 @@ module ActiveRecord
|
|
270
262
|
#
|
271
263
|
# Example:
|
272
264
|
# drop_database('sebastian_development')
|
273
|
-
def drop_database(name)
|
265
|
+
def drop_database(name) # :nodoc:
|
274
266
|
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
|
275
267
|
end
|
276
268
|
|
@@ -346,12 +338,12 @@ module ActiveRecord
|
|
346
338
|
end
|
347
339
|
end
|
348
340
|
|
349
|
-
def change_column_default(table_name, column_name, default_or_changes)
|
341
|
+
def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
|
350
342
|
default = extract_new_default_value(default_or_changes)
|
351
343
|
change_column table_name, column_name, nil, default: default
|
352
344
|
end
|
353
345
|
|
354
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
346
|
+
def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
|
355
347
|
unless null || default.nil?
|
356
348
|
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
357
349
|
end
|
@@ -364,16 +356,16 @@ module ActiveRecord
|
|
364
356
|
change_column table_name, column_name, nil, comment: comment
|
365
357
|
end
|
366
358
|
|
367
|
-
def change_column(table_name, column_name, type, **options)
|
359
|
+
def change_column(table_name, column_name, type, **options) # :nodoc:
|
368
360
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
|
369
361
|
end
|
370
362
|
|
371
|
-
def rename_column(table_name, column_name, new_column_name)
|
363
|
+
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
372
364
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
|
373
365
|
rename_column_indexes(table_name, column_name, new_column_name)
|
374
366
|
end
|
375
367
|
|
376
|
-
def add_index(table_name, column_name, **options)
|
368
|
+
def add_index(table_name, column_name, **options) # :nodoc:
|
377
369
|
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
378
370
|
|
379
371
|
return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
|
@@ -427,7 +419,7 @@ module ActiveRecord
|
|
427
419
|
if supports_check_constraints?
|
428
420
|
scope = quoted_scope(table_name)
|
429
421
|
|
430
|
-
|
422
|
+
sql = <<~SQL
|
431
423
|
SELECT cc.constraint_name AS 'name',
|
432
424
|
cc.check_clause AS 'expression'
|
433
425
|
FROM information_schema.check_constraints cc
|
@@ -437,6 +429,9 @@ module ActiveRecord
|
|
437
429
|
AND tc.table_name = #{scope[:name]}
|
438
430
|
AND cc.constraint_schema = #{scope[:schema]}
|
439
431
|
SQL
|
432
|
+
sql += " AND cc.table_name = #{scope[:name]}" if mariadb?
|
433
|
+
|
434
|
+
chk_info = exec_query(sql, "SCHEMA")
|
440
435
|
|
441
436
|
chk_info.map do |row|
|
442
437
|
options = {
|
@@ -548,8 +543,12 @@ module ActiveRecord
|
|
548
543
|
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
549
544
|
elsif insert.update_duplicates?
|
550
545
|
sql << " ON DUPLICATE KEY UPDATE "
|
551
|
-
|
552
|
-
|
546
|
+
if insert.raw_update_sql?
|
547
|
+
sql << insert.raw_update_sql
|
548
|
+
else
|
549
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
|
550
|
+
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
551
|
+
end
|
553
552
|
end
|
554
553
|
|
555
554
|
sql
|
@@ -561,55 +560,77 @@ module ActiveRecord
|
|
561
560
|
end
|
562
561
|
end
|
563
562
|
|
564
|
-
|
565
|
-
|
566
|
-
|
563
|
+
class << self
|
564
|
+
private
|
565
|
+
def initialize_type_map(m)
|
566
|
+
super
|
567
567
|
|
568
|
-
|
569
|
-
|
570
|
-
|
568
|
+
m.register_type(%r(char)i) do |sql_type|
|
569
|
+
limit = extract_limit(sql_type)
|
570
|
+
Type.lookup(:string, adapter: :mysql2, limit: limit)
|
571
|
+
end
|
572
|
+
|
573
|
+
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
574
|
+
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
575
|
+
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
|
576
|
+
m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
|
577
|
+
m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
|
578
|
+
m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
|
579
|
+
m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
|
580
|
+
m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
|
581
|
+
m.register_type %r(^float)i, Type::Float.new(limit: 24)
|
582
|
+
m.register_type %r(^double)i, Type::Float.new(limit: 53)
|
583
|
+
|
584
|
+
register_integer_type m, %r(^bigint)i, limit: 8
|
585
|
+
register_integer_type m, %r(^int)i, limit: 4
|
586
|
+
register_integer_type m, %r(^mediumint)i, limit: 3
|
587
|
+
register_integer_type m, %r(^smallint)i, limit: 2
|
588
|
+
register_integer_type m, %r(^tinyint)i, limit: 1
|
589
|
+
|
590
|
+
m.alias_type %r(year)i, "integer"
|
591
|
+
m.alias_type %r(bit)i, "binary"
|
592
|
+
|
593
|
+
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
|
594
|
+
m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
|
571
595
|
end
|
572
596
|
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
m.register_type %r(^double)i, Type::Float.new(limit: 53)
|
583
|
-
|
584
|
-
register_integer_type m, %r(^bigint)i, limit: 8
|
585
|
-
register_integer_type m, %r(^int)i, limit: 4
|
586
|
-
register_integer_type m, %r(^mediumint)i, limit: 3
|
587
|
-
register_integer_type m, %r(^smallint)i, limit: 2
|
588
|
-
register_integer_type m, %r(^tinyint)i, limit: 1
|
589
|
-
|
590
|
-
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
|
591
|
-
m.alias_type %r(year)i, "integer"
|
592
|
-
m.alias_type %r(bit)i, "binary"
|
593
|
-
|
594
|
-
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
|
595
|
-
m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
|
596
|
-
end
|
597
|
+
def register_integer_type(mapping, key, **options)
|
598
|
+
mapping.register_type(key) do |sql_type|
|
599
|
+
if /\bunsigned\b/.match?(sql_type)
|
600
|
+
Type::UnsignedInteger.new(**options)
|
601
|
+
else
|
602
|
+
Type::Integer.new(**options)
|
603
|
+
end
|
604
|
+
end
|
605
|
+
end
|
597
606
|
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
Type::UnsignedInteger.new(**options)
|
607
|
+
def extract_precision(sql_type)
|
608
|
+
if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
|
609
|
+
super || 0
|
602
610
|
else
|
603
|
-
|
611
|
+
super
|
604
612
|
end
|
605
613
|
end
|
614
|
+
end
|
615
|
+
|
616
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
617
|
+
TYPE_MAP_WITH_BOOLEAN = Type::TypeMap.new(TYPE_MAP).tap do |m|
|
618
|
+
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
|
619
|
+
end
|
620
|
+
|
621
|
+
private
|
622
|
+
def type_map
|
623
|
+
emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
|
606
624
|
end
|
607
625
|
|
608
|
-
def
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
626
|
+
def raw_execute(sql, name, async: false)
|
627
|
+
materialize_transactions
|
628
|
+
mark_transaction_written_if_write(sql)
|
629
|
+
|
630
|
+
log(sql, name, async: async) do
|
631
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
632
|
+
@connection.query(sql)
|
633
|
+
end
|
613
634
|
end
|
614
635
|
end
|
615
636
|
|
@@ -780,14 +801,13 @@ module ActiveRecord
|
|
780
801
|
end
|
781
802
|
|
782
803
|
# Gather up all of the SET variables...
|
783
|
-
variable_assignments = variables.
|
804
|
+
variable_assignments = variables.filter_map do |k, v|
|
784
805
|
if defaults.include?(v)
|
785
806
|
"@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
|
786
807
|
elsif !v.nil?
|
787
808
|
"@@SESSION.#{k} = #{quote(v)}"
|
788
809
|
end
|
789
|
-
|
790
|
-
end.compact.join(", ")
|
810
|
+
end.join(", ")
|
791
811
|
|
792
812
|
# ...and send them all in one query
|
793
813
|
execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
@@ -839,10 +859,6 @@ module ActiveRecord
|
|
839
859
|
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
840
860
|
end
|
841
861
|
|
842
|
-
# Alias MysqlString to work Mashal.load(File.read("legacy_record.dump")).
|
843
|
-
# TODO: Remove the constant alias once Rails 6.1 has released.
|
844
|
-
MysqlString = Type::String # :nodoc:
|
845
|
-
|
846
862
|
ActiveRecord::Type.register(:immutable_string, adapter: :mysql2) do |_, **args|
|
847
863
|
Type::ImmutableString.new(true: "1", false: "0", **args)
|
848
864
|
end
|
@@ -32,29 +32,24 @@ module ActiveRecord
|
|
32
32
|
|
33
33
|
def explain(arel, binds = [])
|
34
34
|
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
35
|
-
start =
|
35
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
36
36
|
result = exec_query(sql, "EXPLAIN", binds)
|
37
|
-
elapsed =
|
37
|
+
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
38
38
|
|
39
39
|
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
40
40
|
end
|
41
41
|
|
42
42
|
# Executes the SQL statement in the context of this connection.
|
43
|
-
def execute(sql, name = nil)
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
49
|
-
# made since we established the connection
|
50
|
-
@connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
|
43
|
+
def execute(sql, name = nil, async: false)
|
44
|
+
sql = transform_query(sql)
|
45
|
+
check_if_write_query(sql)
|
51
46
|
|
52
|
-
|
47
|
+
raw_execute(sql, name, async: async)
|
53
48
|
end
|
54
49
|
|
55
|
-
def exec_query(sql, name = "SQL", binds = [], prepare: false)
|
50
|
+
def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :nodoc:
|
56
51
|
if without_prepared_statement?(binds)
|
57
|
-
execute_and_free(sql, name) do |result|
|
52
|
+
execute_and_free(sql, name, async: async) do |result|
|
58
53
|
if result
|
59
54
|
build_result(columns: result.fields, rows: result.to_a)
|
60
55
|
else
|
@@ -62,7 +57,7 @@ module ActiveRecord
|
|
62
57
|
end
|
63
58
|
end
|
64
59
|
else
|
65
|
-
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare) do |_, result|
|
60
|
+
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare, async: async) do |_, result|
|
66
61
|
if result
|
67
62
|
build_result(columns: result.fields, rows: result.to_a)
|
68
63
|
else
|
@@ -72,7 +67,7 @@ module ActiveRecord
|
|
72
67
|
end
|
73
68
|
end
|
74
69
|
|
75
|
-
def exec_delete(sql, name = nil, binds = [])
|
70
|
+
def exec_delete(sql, name = nil, binds = []) # :nodoc:
|
76
71
|
if without_prepared_statement?(binds)
|
77
72
|
@lock.synchronize do
|
78
73
|
execute_and_free(sql, name) { @connection.affected_rows }
|
@@ -83,10 +78,28 @@ module ActiveRecord
|
|
83
78
|
end
|
84
79
|
alias :exec_update :exec_delete
|
85
80
|
|
81
|
+
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_current-timestamp
|
82
|
+
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-syntax.html
|
83
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP(6)").freeze # :nodoc:
|
84
|
+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
85
|
+
|
86
|
+
def high_precision_current_timestamp
|
87
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP
|
88
|
+
end
|
89
|
+
|
86
90
|
private
|
91
|
+
def raw_execute(sql, name, async: false)
|
92
|
+
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
93
|
+
# made since we established the connection
|
94
|
+
@connection.query_options[:database_timezone] = ActiveRecord.default_timezone
|
95
|
+
|
96
|
+
super
|
97
|
+
end
|
98
|
+
|
87
99
|
def execute_batch(statements, name = nil)
|
100
|
+
statements = statements.map { |sql| transform_query(sql) }
|
88
101
|
combine_multi_statements(statements).each do |statement|
|
89
|
-
|
102
|
+
raw_execute(statement, name)
|
90
103
|
end
|
91
104
|
@connection.abandon_results!
|
92
105
|
end
|
@@ -150,21 +163,20 @@ module ActiveRecord
|
|
150
163
|
@max_allowed_packet ||= show_variable("max_allowed_packet")
|
151
164
|
end
|
152
165
|
|
153
|
-
def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
|
154
|
-
|
155
|
-
|
156
|
-
end
|
166
|
+
def exec_stmt_and_free(sql, name, binds, cache_stmt: false, async: false)
|
167
|
+
sql = transform_query(sql)
|
168
|
+
check_if_write_query(sql)
|
157
169
|
|
158
170
|
materialize_transactions
|
159
171
|
mark_transaction_written_if_write(sql)
|
160
172
|
|
161
|
-
# make sure we carry over any changes to ActiveRecord
|
173
|
+
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
162
174
|
# made since we established the connection
|
163
|
-
@connection.query_options[:database_timezone] = ActiveRecord
|
175
|
+
@connection.query_options[:database_timezone] = ActiveRecord.default_timezone
|
164
176
|
|
165
177
|
type_casted_binds = type_casted_binds(binds)
|
166
178
|
|
167
|
-
log(sql, name, binds, type_casted_binds) do
|
179
|
+
log(sql, name, binds, type_casted_binds, async: async) do
|
168
180
|
if cache_stmt
|
169
181
|
stmt = @statements[sql] ||= @connection.prepare(sql)
|
170
182
|
else
|
@@ -6,6 +6,21 @@ module ActiveRecord
|
|
6
6
|
module ConnectionAdapters
|
7
7
|
module MySQL
|
8
8
|
module Quoting # :nodoc:
|
9
|
+
def quote_bound_value(value)
|
10
|
+
case value
|
11
|
+
when Numeric
|
12
|
+
quote(value.to_s)
|
13
|
+
when BigDecimal
|
14
|
+
quote(value.to_s("F"))
|
15
|
+
when true
|
16
|
+
"'1'"
|
17
|
+
when false
|
18
|
+
"'0'"
|
19
|
+
else
|
20
|
+
quote(value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
9
24
|
def quote_column_name(name)
|
10
25
|
self.class.quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`"
|
11
26
|
end
|
@@ -34,6 +49,26 @@ module ActiveRecord
|
|
34
49
|
"x'#{value.hex}'"
|
35
50
|
end
|
36
51
|
|
52
|
+
# Override +type_cast+ we pass to mysql2 Date and Time objects instead
|
53
|
+
# of Strings since mysql2 is able to handle those classes more efficiently.
|
54
|
+
def type_cast(value) # :nodoc:
|
55
|
+
case value
|
56
|
+
when ActiveSupport::TimeWithZone
|
57
|
+
# We need to check explicitly for ActiveSupport::TimeWithZone because
|
58
|
+
# we need to transform it to Time objects but we don't want to
|
59
|
+
# transform Time objects to themselves.
|
60
|
+
if ActiveRecord.default_timezone == :utc
|
61
|
+
value.getutc
|
62
|
+
else
|
63
|
+
value.getlocal
|
64
|
+
end
|
65
|
+
when Date, Time
|
66
|
+
value
|
67
|
+
else
|
68
|
+
super
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
37
72
|
def column_name_matcher
|
38
73
|
COLUMN_NAME
|
39
74
|
end
|
@@ -69,27 +104,6 @@ module ActiveRecord
|
|
69
104
|
/ix
|
70
105
|
|
71
106
|
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
72
|
-
|
73
|
-
private
|
74
|
-
# Override +_type_cast+ we pass to mysql2 Date and Time objects instead
|
75
|
-
# of Strings since mysql2 is able to handle those classes more efficiently.
|
76
|
-
def _type_cast(value)
|
77
|
-
case value
|
78
|
-
when ActiveSupport::TimeWithZone
|
79
|
-
# We need to check explicitly for ActiveSupport::TimeWithZone because
|
80
|
-
# we need to transform it to Time objects but we don't want to
|
81
|
-
# transform Time objects to themselves.
|
82
|
-
if ActiveRecord::Base.default_timezone == :utc
|
83
|
-
value.getutc
|
84
|
-
else
|
85
|
-
value.getlocal
|
86
|
-
end
|
87
|
-
when Date, Time
|
88
|
-
value
|
89
|
-
else
|
90
|
-
super
|
91
|
-
end
|
92
|
-
end
|
93
107
|
end
|
94
108
|
end
|
95
109
|
end
|
@@ -30,7 +30,11 @@ module ActiveRecord
|
|
30
30
|
|
31
31
|
module ConnectionAdapters
|
32
32
|
class Mysql2Adapter < AbstractMysqlAdapter
|
33
|
-
ER_BAD_DB_ERROR
|
33
|
+
ER_BAD_DB_ERROR = 1049
|
34
|
+
ER_ACCESS_DENIED_ERROR = 1045
|
35
|
+
ER_CONN_HOST_ERROR = 2003
|
36
|
+
ER_UNKNOWN_HOST_ERROR = 2005
|
37
|
+
|
34
38
|
ADAPTER_NAME = "Mysql2"
|
35
39
|
|
36
40
|
include MySQL::DatabaseStatements
|
@@ -40,7 +44,11 @@ module ActiveRecord
|
|
40
44
|
Mysql2::Client.new(config)
|
41
45
|
rescue Mysql2::Error => error
|
42
46
|
if error.error_number == ConnectionAdapters::Mysql2Adapter::ER_BAD_DB_ERROR
|
43
|
-
raise ActiveRecord::NoDatabaseError
|
47
|
+
raise ActiveRecord::NoDatabaseError.db_error(config[:database])
|
48
|
+
elsif error.error_number == ConnectionAdapters::Mysql2Adapter::ER_ACCESS_DENIED_ERROR
|
49
|
+
raise ActiveRecord::DatabaseConnectionError.username_error(config[:username])
|
50
|
+
elsif [ConnectionAdapters::Mysql2Adapter::ER_CONN_HOST_ERROR, ConnectionAdapters::Mysql2Adapter::ER_UNKNOWN_HOST_ERROR].include?(error.error_number)
|
51
|
+
raise ActiveRecord::DatabaseConnectionError.hostname_error(config[:host])
|
44
52
|
else
|
45
53
|
raise ActiveRecord::ConnectionNotEstablished, error.message
|
46
54
|
end
|
@@ -81,11 +89,9 @@ module ActiveRecord
|
|
81
89
|
|
82
90
|
# HELPER METHODS ===========================================
|
83
91
|
|
84
|
-
def each_hash(result) # :nodoc:
|
92
|
+
def each_hash(result, &block) # :nodoc:
|
85
93
|
if block_given?
|
86
|
-
result.each(as: :hash, symbolize_keys: true)
|
87
|
-
yield row
|
88
|
-
end
|
94
|
+
result.each(as: :hash, symbolize_keys: true, &block)
|
89
95
|
else
|
90
96
|
to_enum(:each_hash, result)
|
91
97
|
end
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
class PoolConfig # :nodoc:
|
6
6
|
include Mutex_m
|
7
7
|
|
8
|
-
attr_reader :db_config, :
|
8
|
+
attr_reader :db_config, :connection_class, :role, :shard
|
9
9
|
attr_accessor :schema_cache
|
10
10
|
|
11
11
|
INSTANCES = ObjectSpace::WeakMap.new
|
@@ -17,21 +17,21 @@ module ActiveRecord
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def initialize(
|
20
|
+
def initialize(connection_class, db_config, role, shard)
|
21
21
|
super()
|
22
|
-
@
|
22
|
+
@connection_class = connection_class
|
23
23
|
@db_config = db_config
|
24
|
+
@role = role
|
25
|
+
@shard = shard
|
24
26
|
@pool = nil
|
25
27
|
INSTANCES[self] = self
|
26
28
|
end
|
27
29
|
|
28
30
|
def connection_specification_name
|
29
|
-
if
|
30
|
-
connection_klass
|
31
|
-
elsif connection_klass.primary_class?
|
31
|
+
if connection_class.primary_class?
|
32
32
|
"ActiveRecord::Base"
|
33
33
|
else
|
34
|
-
|
34
|
+
connection_class.name
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -1,25 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/object/blank"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module ConnectionAdapters
|
5
7
|
module PostgreSQL
|
6
8
|
class Column < ConnectionAdapters::Column # :nodoc:
|
7
9
|
delegate :oid, :fmod, to: :sql_type_metadata
|
8
10
|
|
9
|
-
def initialize(*, serial: nil, **)
|
11
|
+
def initialize(*, serial: nil, generated: nil, **)
|
10
12
|
super
|
11
13
|
@serial = serial
|
14
|
+
@generated = generated
|
12
15
|
end
|
13
16
|
|
14
17
|
def serial?
|
15
18
|
@serial
|
16
19
|
end
|
17
20
|
|
21
|
+
def virtual?
|
22
|
+
# We assume every generated column is virtual, no matter the concrete type
|
23
|
+
@generated.present?
|
24
|
+
end
|
25
|
+
|
26
|
+
def has_default?
|
27
|
+
super && !virtual?
|
28
|
+
end
|
29
|
+
|
18
30
|
def array
|
19
31
|
sql_type_metadata.sql_type.end_with?("[]")
|
20
32
|
end
|
21
33
|
alias :array? :array
|
22
34
|
|
35
|
+
def enum?
|
36
|
+
type == :enum
|
37
|
+
end
|
38
|
+
|
23
39
|
def sql_type
|
24
40
|
super.delete_suffix("[]")
|
25
41
|
end
|