activerecord 7.2.2.1 → 8.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +564 -753
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/association.rb +35 -11
- data/lib/active_record/associations/belongs_to_association.rb +18 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +17 -4
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +10 -8
- data/lib/active_record/associations/collection_proxy.rb +22 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/associations/join_dependency.rb +4 -2
- data/lib/active_record/associations/preloader/association.rb +2 -2
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +1 -0
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +192 -24
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/primary_key.rb +4 -8
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +17 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
- data/lib/active_record/attribute_methods.rb +24 -19
- data/lib/active_record/attributes.rb +40 -26
- data/lib/active_record/autosave_association.rb +91 -39
- data/lib/active_record/base.rb +3 -4
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +458 -117
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +136 -74
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +44 -11
- data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -29
- data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
- data/lib/active_record/connection_adapters/abstract_adapter.rb +175 -87
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +77 -58
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +73 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -11
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +28 -45
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +140 -64
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +13 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +112 -42
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +2 -19
- data/lib/active_record/connection_adapters.rb +1 -56
- data/lib/active_record/connection_handling.rb +37 -10
- data/lib/active_record/core.rb +61 -25
- data/lib/active_record/counter_cache.rb +34 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/database_configurations/database_config.rb +9 -1
- data/lib/active_record/database_configurations/hash_config.rb +67 -9
- data/lib/active_record/database_configurations/url_config.rb +13 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +19 -19
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +9 -9
- data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
- data/lib/active_record/encryption/encryptor.rb +49 -28
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +9 -2
- data/lib/active_record/enum.rb +46 -42
- data/lib/active_record/errors.rb +36 -12
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +73 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +2 -4
- data/lib/active_record/future_result.rb +13 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/insert_all.rb +12 -7
- data/lib/active_record/locking/optimistic.rb +8 -1
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +3 -13
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +44 -11
- data/lib/active_record/migration/compatibility.rb +37 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +50 -43
- data/lib/active_record/model_schema.rb +38 -13
- data/lib/active_record/nested_attributes.rb +6 -6
- data/lib/active_record/persistence.rb +162 -133
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +104 -52
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +12 -12
- data/lib/active_record/railtie.rb +37 -32
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +26 -37
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +53 -21
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +147 -73
- data/lib/active_record/relation/calculations.rb +80 -63
- data/lib/active_record/relation/delegation.rb +25 -15
- data/lib/active_record/relation/finder_methods.rb +54 -37
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +22 -7
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +156 -95
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +10 -11
- data/lib/active_record/relation.rb +122 -80
- data/lib/active_record/result.rb +109 -24
- data/lib/active_record/runtime_registry.rb +42 -58
- data/lib/active_record/sanitization.rb +9 -6
- data/lib/active_record/schema_dumper.rb +47 -22
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +47 -18
- data/lib/active_record/statement_cache.rb +24 -20
- data/lib/active_record/store.rb +51 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +6 -23
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +85 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +39 -2
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +39 -16
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +15 -2
- data/lib/active_record/type/serialized.rb +11 -4
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +2 -1
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +85 -50
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/node.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/select_manager.rb +13 -4
- data/lib/arel/table.rb +3 -7
- data/lib/arel/update_manager.rb +5 -0
- data/lib/arel/visitors/dot.rb +2 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +6 -22
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +17 -17
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -163
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
|
@@ -42,7 +42,7 @@ module ActiveRecord
|
|
|
42
42
|
date: { name: "date" },
|
|
43
43
|
binary: { name: "blob" },
|
|
44
44
|
blob: { name: "blob" },
|
|
45
|
-
boolean: { name: "
|
|
45
|
+
boolean: { name: "boolean" },
|
|
46
46
|
json: { name: "json" },
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -79,7 +79,11 @@ module ActiveRecord
|
|
|
79
79
|
|
|
80
80
|
args << config.database
|
|
81
81
|
|
|
82
|
-
find_cmd_and_exec([
|
|
82
|
+
find_cmd_and_exec(ActiveRecord.database_cli[:mysql], *args)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def native_database_types # :nodoc:
|
|
86
|
+
NATIVE_DATABASE_TYPES
|
|
83
87
|
end
|
|
84
88
|
end
|
|
85
89
|
|
|
@@ -98,7 +102,7 @@ module ActiveRecord
|
|
|
98
102
|
end
|
|
99
103
|
|
|
100
104
|
def supports_index_sort_order?
|
|
101
|
-
|
|
105
|
+
mariadb? ? database_version >= "10.8.1" : database_version >= "8.0.1"
|
|
102
106
|
end
|
|
103
107
|
|
|
104
108
|
def supports_expression_index?
|
|
@@ -138,7 +142,7 @@ module ActiveRecord
|
|
|
138
142
|
end
|
|
139
143
|
|
|
140
144
|
def supports_datetime_with_precision?
|
|
141
|
-
|
|
145
|
+
true
|
|
142
146
|
end
|
|
143
147
|
|
|
144
148
|
def supports_virtual_columns?
|
|
@@ -174,6 +178,20 @@ module ActiveRecord
|
|
|
174
178
|
mariadb? && database_version >= "10.5.0"
|
|
175
179
|
end
|
|
176
180
|
|
|
181
|
+
def return_value_after_insert?(column) # :nodoc:
|
|
182
|
+
supports_insert_returning? ? column.auto_populated? : column.auto_increment?
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# See https://dev.mysql.com/doc/refman/8.0/en/invisible-indexes.html for more details on MySQL feature.
|
|
186
|
+
# See https://mariadb.com/kb/en/ignored-indexes/ for more details on the MariaDB feature.
|
|
187
|
+
def supports_disabling_indexes?
|
|
188
|
+
if mariadb?
|
|
189
|
+
database_version >= "10.6.0"
|
|
190
|
+
else
|
|
191
|
+
database_version >= "8.0.0"
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
177
195
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
|
178
196
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
|
179
197
|
end
|
|
@@ -182,10 +200,6 @@ module ActiveRecord
|
|
|
182
200
|
query_value("SELECT RELEASE_LOCK(#{quote(lock_name.to_s)})") == 1
|
|
183
201
|
end
|
|
184
202
|
|
|
185
|
-
def native_database_types
|
|
186
|
-
NATIVE_DATABASE_TYPES
|
|
187
|
-
end
|
|
188
|
-
|
|
189
203
|
def index_algorithms
|
|
190
204
|
{
|
|
191
205
|
default: "ALGORITHM = DEFAULT",
|
|
@@ -195,14 +209,6 @@ module ActiveRecord
|
|
|
195
209
|
}
|
|
196
210
|
end
|
|
197
211
|
|
|
198
|
-
# HELPER METHODS ===========================================
|
|
199
|
-
|
|
200
|
-
# The two drivers have slightly different ways of yielding hashes of results, so
|
|
201
|
-
# this method must be implemented to provide a uniform interface.
|
|
202
|
-
def each_hash(result) # :nodoc:
|
|
203
|
-
raise NotImplementedError
|
|
204
|
-
end
|
|
205
|
-
|
|
206
212
|
# Must return the MySQL error number from the exception, if the exception has an
|
|
207
213
|
# error number.
|
|
208
214
|
def error_number(exception) # :nodoc:
|
|
@@ -226,24 +232,19 @@ module ActiveRecord
|
|
|
226
232
|
# DATABASE STATEMENTS ======================================
|
|
227
233
|
#++
|
|
228
234
|
|
|
229
|
-
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
|
230
|
-
# to write stuff in an abstract way without concerning ourselves about whether it
|
|
231
|
-
# needs to be explicitly freed or not.
|
|
232
|
-
def execute_and_free(sql, name = nil, async: false, allow_retry: false) # :nodoc:
|
|
233
|
-
sql = transform_query(sql)
|
|
234
|
-
check_if_write_query(sql)
|
|
235
|
-
|
|
236
|
-
mark_transaction_written_if_write(sql)
|
|
237
|
-
yield raw_execute(sql, name, async: async, allow_retry: allow_retry)
|
|
238
|
-
end
|
|
239
|
-
|
|
240
235
|
def begin_db_transaction # :nodoc:
|
|
241
236
|
internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
242
237
|
end
|
|
243
238
|
|
|
244
239
|
def begin_isolated_db_transaction(isolation) # :nodoc:
|
|
245
|
-
|
|
246
|
-
|
|
240
|
+
# From MySQL manual: The [SET TRANSACTION] statement applies only to the next single transaction performed within the session.
|
|
241
|
+
# So we don't need to implement #reset_isolation_level
|
|
242
|
+
execute_batch(
|
|
243
|
+
["SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "BEGIN"],
|
|
244
|
+
"TRANSACTION",
|
|
245
|
+
allow_retry: true,
|
|
246
|
+
materialize_transactions: false,
|
|
247
|
+
)
|
|
247
248
|
end
|
|
248
249
|
|
|
249
250
|
def commit_db_transaction # :nodoc:
|
|
@@ -343,7 +344,7 @@ module ActiveRecord
|
|
|
343
344
|
rename_table_indexes(table_name, new_name, **options)
|
|
344
345
|
end
|
|
345
346
|
|
|
346
|
-
# Drops a table from the database.
|
|
347
|
+
# Drops a table or tables from the database.
|
|
347
348
|
#
|
|
348
349
|
# [<tt>:force</tt>]
|
|
349
350
|
# Set to +:cascade+ to drop dependent objects as well.
|
|
@@ -357,10 +358,10 @@ module ActiveRecord
|
|
|
357
358
|
#
|
|
358
359
|
# Although this command ignores most +options+ and the block if one is given,
|
|
359
360
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
|
360
|
-
# In that case, +options+ and the block will be used by create_table.
|
|
361
|
-
def drop_table(
|
|
362
|
-
schema_cache.clear_data_source_cache!(table_name.to_s)
|
|
363
|
-
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
|
|
361
|
+
# In that case, +options+ and the block will be used by #create_table except if you provide more than one table which is not supported.
|
|
362
|
+
def drop_table(*table_names, **options)
|
|
363
|
+
table_names.each { |table_name| schema_cache.clear_data_source_cache!(table_name.to_s) }
|
|
364
|
+
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{table_names.map { |table_name| quote_table_name(table_name) }.join(', ')}#{' CASCADE' if options[:force] == :cascade}"
|
|
364
365
|
end
|
|
365
366
|
|
|
366
367
|
def rename_index(table_name, old_name, new_name)
|
|
@@ -414,7 +415,11 @@ module ActiveRecord
|
|
|
414
415
|
type ||= column.sql_type
|
|
415
416
|
|
|
416
417
|
unless options.key?(:default)
|
|
417
|
-
options[:default] = column.
|
|
418
|
+
options[:default] = if column.default_function
|
|
419
|
+
-> { column.default_function }
|
|
420
|
+
else
|
|
421
|
+
column.default
|
|
422
|
+
end
|
|
418
423
|
end
|
|
419
424
|
|
|
420
425
|
unless options.key?(:null)
|
|
@@ -460,6 +465,24 @@ module ActiveRecord
|
|
|
460
465
|
CreateIndexDefinition.new(index, algorithm)
|
|
461
466
|
end
|
|
462
467
|
|
|
468
|
+
def enable_index(table_name, index_name) # :nodoc:
|
|
469
|
+
raise NotImplementedError unless supports_disabling_indexes?
|
|
470
|
+
|
|
471
|
+
query = <<~SQL
|
|
472
|
+
ALTER TABLE #{quote_table_name(table_name)} ALTER INDEX #{index_name} #{mariadb? ? "NOT IGNORED" : "VISIBLE"}
|
|
473
|
+
SQL
|
|
474
|
+
execute(query)
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def disable_index(table_name, index_name) # :nodoc:
|
|
478
|
+
raise NotImplementedError unless supports_disabling_indexes?
|
|
479
|
+
|
|
480
|
+
query = <<~SQL
|
|
481
|
+
ALTER TABLE #{quote_table_name(table_name)} ALTER INDEX #{index_name} #{mariadb? ? "IGNORED" : "INVISIBLE"}
|
|
482
|
+
SQL
|
|
483
|
+
execute(query)
|
|
484
|
+
end
|
|
485
|
+
|
|
463
486
|
def add_sql_comment!(sql, comment) # :nodoc:
|
|
464
487
|
sql << " COMMENT #{quote(comment)}" if comment.present?
|
|
465
488
|
sql
|
|
@@ -580,7 +603,7 @@ module ActiveRecord
|
|
|
580
603
|
|
|
581
604
|
# SHOW VARIABLES LIKE 'name'
|
|
582
605
|
def show_variable(name)
|
|
583
|
-
query_value("SELECT @@#{name}", "SCHEMA")
|
|
606
|
+
query_value("SELECT @@#{name}", "SCHEMA", materialize_transactions: false, allow_retry: true)
|
|
584
607
|
rescue ActiveRecord::StatementInvalid
|
|
585
608
|
nil
|
|
586
609
|
end
|
|
@@ -639,24 +662,26 @@ module ActiveRecord
|
|
|
639
662
|
end
|
|
640
663
|
|
|
641
664
|
def build_insert_sql(insert) # :nodoc:
|
|
665
|
+
# Can use any column as it will be assigned to itself.
|
|
642
666
|
no_op_column = quote_column_name(insert.keys.first) if insert.keys.first
|
|
643
667
|
|
|
644
668
|
# MySQL 8.0.19 replaces `VALUES(<expression>)` clauses with row and column alias names, see https://dev.mysql.com/worklog/task/?id=6312 .
|
|
645
669
|
# then MySQL 8.0.20 deprecates the `VALUES(<expression>)` see https://dev.mysql.com/worklog/task/?id=13325 .
|
|
646
670
|
if supports_insert_raw_alias_syntax?
|
|
671
|
+
quoted_table_name = insert.model.quoted_table_name
|
|
647
672
|
values_alias = quote_table_name("#{insert.model.table_name.parameterize}_values")
|
|
648
673
|
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"
|
|
649
674
|
|
|
650
675
|
if insert.skip_duplicates?
|
|
651
676
|
if no_op_column
|
|
652
|
-
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{
|
|
677
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{quoted_table_name}.#{no_op_column}"
|
|
653
678
|
end
|
|
654
679
|
elsif insert.update_duplicates?
|
|
655
680
|
if insert.raw_update_sql?
|
|
656
681
|
sql = +"INSERT #{insert.into} #{insert.values_list} ON DUPLICATE KEY UPDATE #{insert.raw_update_sql}"
|
|
657
682
|
else
|
|
658
683
|
sql << " ON DUPLICATE KEY UPDATE "
|
|
659
|
-
sql << insert.touch_model_timestamps_unless { |column| "#{
|
|
684
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{quoted_table_name}.#{column}<=>#{values_alias}.#{column}" }
|
|
660
685
|
sql << insert.updatable_columns.map { |column| "#{column}=#{values_alias}.#{column}" }.join(",")
|
|
661
686
|
end
|
|
662
687
|
end
|
|
@@ -683,8 +708,8 @@ module ActiveRecord
|
|
|
683
708
|
end
|
|
684
709
|
|
|
685
710
|
def check_version # :nodoc:
|
|
686
|
-
if database_version < "5.
|
|
687
|
-
raise DatabaseVersionError, "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.
|
|
711
|
+
if database_version < "5.6.4"
|
|
712
|
+
raise DatabaseVersionError, "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.6.4."
|
|
688
713
|
end
|
|
689
714
|
end
|
|
690
715
|
|
|
@@ -733,12 +758,12 @@ module ActiveRecord
|
|
|
733
758
|
m.alias_type %r(bit)i, "binary"
|
|
734
759
|
end
|
|
735
760
|
|
|
736
|
-
def register_integer_type(mapping, key,
|
|
761
|
+
def register_integer_type(mapping, key, limit:)
|
|
737
762
|
mapping.register_type(key) do |sql_type|
|
|
738
763
|
if /\bunsigned\b/.match?(sql_type)
|
|
739
|
-
Type::UnsignedInteger.new(
|
|
764
|
+
Type::UnsignedInteger.new(limit: limit)
|
|
740
765
|
else
|
|
741
|
-
Type::Integer.new(
|
|
766
|
+
Type::Integer.new(limit: limit)
|
|
742
767
|
end
|
|
743
768
|
end
|
|
744
769
|
end
|
|
@@ -757,9 +782,7 @@ module ActiveRecord
|
|
|
757
782
|
|
|
758
783
|
private
|
|
759
784
|
def strip_whitespace_characters(expression)
|
|
760
|
-
expression
|
|
761
|
-
expression = expression.gsub(/\s{2,}/, " ")
|
|
762
|
-
expression
|
|
785
|
+
expression.gsub('\\\n', "").gsub("x0A", "").squish
|
|
763
786
|
end
|
|
764
787
|
|
|
765
788
|
def extended_type_map_key
|
|
@@ -770,14 +793,13 @@ module ActiveRecord
|
|
|
770
793
|
end
|
|
771
794
|
end
|
|
772
795
|
|
|
773
|
-
def handle_warnings(sql)
|
|
796
|
+
def handle_warnings(_initial_result, sql)
|
|
774
797
|
return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
|
|
775
798
|
|
|
776
|
-
@affected_rows_before_warnings = @raw_connection.affected_rows
|
|
777
799
|
warning_count = @raw_connection.warning_count
|
|
778
800
|
result = @raw_connection.query("SHOW WARNINGS")
|
|
779
801
|
result = [
|
|
780
|
-
["Warning", nil, "Query had warning_count=#{warning_count} but
|
|
802
|
+
["Warning", nil, "Query had warning_count=#{warning_count} but `SHOW WARNINGS` did not return the warnings. Check MySQL logs or database configuration."],
|
|
781
803
|
] if result.count == 0
|
|
782
804
|
result.each do |level, code, message|
|
|
783
805
|
warning = SQLWarning.new(message, code, level, sql, @pool)
|
|
@@ -791,11 +813,6 @@ module ActiveRecord
|
|
|
791
813
|
warning.level == "Note" || super
|
|
792
814
|
end
|
|
793
815
|
|
|
794
|
-
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
|
795
|
-
# made since we established the connection
|
|
796
|
-
def sync_timezone_changes(raw_connection)
|
|
797
|
-
end
|
|
798
|
-
|
|
799
816
|
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
|
|
800
817
|
ER_DB_CREATE_EXISTS = 1007
|
|
801
818
|
ER_FILSORT_ABORT = 1028
|
|
@@ -819,6 +836,8 @@ module ActiveRecord
|
|
|
819
836
|
CR_SERVER_LOST = 2013
|
|
820
837
|
ER_QUERY_TIMEOUT = 3024
|
|
821
838
|
ER_FK_INCOMPATIBLE_COLUMNS = 3780
|
|
839
|
+
ER_CHECK_CONSTRAINT_VIOLATED = 3819
|
|
840
|
+
ER_CONSTRAINT_FAILED = 4025
|
|
822
841
|
ER_CLIENT_INTERACTION_TIMEOUT = 4031
|
|
823
842
|
|
|
824
843
|
def translate_exception(exception, message:, sql:, binds:)
|
|
@@ -851,6 +870,8 @@ module ActiveRecord
|
|
|
851
870
|
RangeError.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
852
871
|
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
|
853
872
|
NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
873
|
+
when ER_CHECK_CONSTRAINT_VIOLATED, ER_CONSTRAINT_FAILED
|
|
874
|
+
CheckViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
854
875
|
when ER_LOCK_DEADLOCK
|
|
855
876
|
Deadlocked.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
856
877
|
when ER_LOCK_WAIT_TIMEOUT
|
|
@@ -965,13 +986,11 @@ module ActiveRecord
|
|
|
965
986
|
end.join(", ")
|
|
966
987
|
|
|
967
988
|
# ...and send them all in one query
|
|
968
|
-
|
|
989
|
+
raw_execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
|
969
990
|
end
|
|
970
991
|
|
|
971
992
|
def column_definitions(table_name) # :nodoc:
|
|
972
|
-
|
|
973
|
-
each_hash(result)
|
|
974
|
-
end
|
|
993
|
+
internal_exec_query("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", "SCHEMA", allow_retry: true)
|
|
975
994
|
end
|
|
976
995
|
|
|
977
996
|
def create_table_info(table_name) # :nodoc:
|
|
@@ -17,16 +17,22 @@ module ActiveRecord
|
|
|
17
17
|
# +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
|
|
18
18
|
# +sql_type_metadata+ is various information about the type of the column
|
|
19
19
|
# +null+ determines if this column allows +NULL+ values.
|
|
20
|
-
def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil, **)
|
|
20
|
+
def initialize(name, cast_type, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil, **)
|
|
21
21
|
@name = name.freeze
|
|
22
|
+
@cast_type = cast_type
|
|
22
23
|
@sql_type_metadata = sql_type_metadata
|
|
23
24
|
@null = null
|
|
24
|
-
@default = default
|
|
25
|
+
@default = default.nil? || cast_type.mutable? ? default : cast_type.deserialize(default)
|
|
25
26
|
@default_function = default_function
|
|
26
27
|
@collation = collation
|
|
27
28
|
@comment = comment
|
|
28
29
|
end
|
|
29
30
|
|
|
31
|
+
def fetch_cast_type(connection) # :nodoc:
|
|
32
|
+
# TODO: Remove fetch_cast_type and the need for connection after we release 8.1.
|
|
33
|
+
@cast_type || connection.lookup_cast_type(sql_type)
|
|
34
|
+
end
|
|
35
|
+
|
|
30
36
|
def has_default?
|
|
31
37
|
!default.nil? || default_function
|
|
32
38
|
end
|
|
@@ -45,6 +51,7 @@ module ActiveRecord
|
|
|
45
51
|
|
|
46
52
|
def init_with(coder)
|
|
47
53
|
@name = coder["name"]
|
|
54
|
+
@cast_type = coder["cast_type"]
|
|
48
55
|
@sql_type_metadata = coder["sql_type_metadata"]
|
|
49
56
|
@null = coder["null"]
|
|
50
57
|
@default = coder["default"]
|
|
@@ -55,6 +62,7 @@ module ActiveRecord
|
|
|
55
62
|
|
|
56
63
|
def encode_with(coder)
|
|
57
64
|
coder["name"] = @name
|
|
65
|
+
coder["cast_type"] = @cast_type
|
|
58
66
|
coder["sql_type_metadata"] = @sql_type_metadata
|
|
59
67
|
coder["null"] = @null
|
|
60
68
|
coder["default"] = @default
|
|
@@ -75,6 +83,7 @@ module ActiveRecord
|
|
|
75
83
|
def ==(other)
|
|
76
84
|
other.is_a?(Column) &&
|
|
77
85
|
name == other.name &&
|
|
86
|
+
cast_type == other.cast_type &&
|
|
78
87
|
default == other.default &&
|
|
79
88
|
sql_type_metadata == other.sql_type_metadata &&
|
|
80
89
|
null == other.null &&
|
|
@@ -88,6 +97,7 @@ module ActiveRecord
|
|
|
88
97
|
Column.hash ^
|
|
89
98
|
name.hash ^
|
|
90
99
|
name.encoding.hash ^
|
|
100
|
+
cast_type.hash ^
|
|
91
101
|
default.hash ^
|
|
92
102
|
sql_type_metadata.hash ^
|
|
93
103
|
null.hash ^
|
|
@@ -100,11 +110,14 @@ module ActiveRecord
|
|
|
100
110
|
false
|
|
101
111
|
end
|
|
102
112
|
|
|
113
|
+
protected
|
|
114
|
+
attr_reader :cast_type
|
|
115
|
+
|
|
103
116
|
private
|
|
104
117
|
def deduplicated
|
|
105
118
|
@name = -name
|
|
106
119
|
@sql_type_metadata = sql_type_metadata.deduplicate if sql_type_metadata
|
|
107
|
-
@default = -default if default
|
|
120
|
+
@default = -default if String === default
|
|
108
121
|
@default_function = -default_function if default_function
|
|
109
122
|
@collation = -collation if collation
|
|
110
123
|
@comment = -comment if comment
|
|
@@ -114,7 +127,7 @@ module ActiveRecord
|
|
|
114
127
|
|
|
115
128
|
class NullColumn < Column
|
|
116
129
|
def initialize(name, **)
|
|
117
|
-
super(name, nil)
|
|
130
|
+
super(name, nil, nil)
|
|
118
131
|
end
|
|
119
132
|
end
|
|
120
133
|
end
|
|
@@ -45,16 +45,16 @@ module ActiveRecord
|
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
def default_insert_value(column) # :nodoc:
|
|
49
|
+
super unless column.auto_increment?
|
|
50
|
+
end
|
|
51
|
+
|
|
48
52
|
private
|
|
49
53
|
# https://mariadb.com/kb/en/analyze-statement/
|
|
50
54
|
def analyze_without_explain?
|
|
51
55
|
mariadb? && database_version >= "10.1.0"
|
|
52
56
|
end
|
|
53
57
|
|
|
54
|
-
def default_insert_value(column)
|
|
55
|
-
super unless column.auto_increment?
|
|
56
|
-
end
|
|
57
|
-
|
|
58
58
|
def returning_column_values(result)
|
|
59
59
|
if supports_insert_returning?
|
|
60
60
|
result.rows.first
|
|
@@ -77,14 +77,6 @@ module ActiveRecord
|
|
|
77
77
|
0
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
def quoted_date(value)
|
|
81
|
-
if supports_datetime_with_precision?
|
|
82
|
-
super
|
|
83
|
-
else
|
|
84
|
-
super.sub(/\.\d{6}\z/, "")
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
80
|
def quoted_binary(value)
|
|
89
81
|
"x'#{value.hex}'"
|
|
90
82
|
end
|
|
@@ -110,7 +102,13 @@ module ActiveRecord
|
|
|
110
102
|
else
|
|
111
103
|
value.getlocal
|
|
112
104
|
end
|
|
113
|
-
when
|
|
105
|
+
when Time
|
|
106
|
+
if default_timezone == :utc
|
|
107
|
+
value.utc? ? value : value.getutc
|
|
108
|
+
else
|
|
109
|
+
value.utc? ? value.getlocal : value
|
|
110
|
+
end
|
|
111
|
+
when Date
|
|
114
112
|
value
|
|
115
113
|
else
|
|
116
114
|
super
|
|
@@ -49,6 +49,8 @@ module ActiveRecord
|
|
|
49
49
|
sql << "USING #{o.using}" if o.using
|
|
50
50
|
sql << "ON #{quote_table_name(o.table)}" if create
|
|
51
51
|
sql << "(#{quoted_columns(o)})"
|
|
52
|
+
sql << "INVISIBLE" if o.disabled? && !mariadb?
|
|
53
|
+
sql << "IGNORED" if o.disabled? && mariadb?
|
|
52
54
|
|
|
53
55
|
add_sql_comment!(sql.join(" "), o.comment)
|
|
54
56
|
end
|
|
@@ -5,6 +5,7 @@ module ActiveRecord
|
|
|
5
5
|
module MySQL
|
|
6
6
|
module ColumnMethods
|
|
7
7
|
extend ActiveSupport::Concern
|
|
8
|
+
extend ConnectionAdapters::ColumnMethods::ClassMethods
|
|
8
9
|
|
|
9
10
|
##
|
|
10
11
|
# :method: blob
|
|
@@ -42,18 +43,26 @@ module ActiveRecord
|
|
|
42
43
|
# :method: unsigned_bigint
|
|
43
44
|
# :call-seq: unsigned_bigint(*names, **options)
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
define_column_methods :blob, :tinyblob, :mediumblob, :longblob,
|
|
47
|
+
:tinytext, :mediumtext, :longtext, :unsigned_integer, :unsigned_bigint
|
|
48
|
+
end
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
# = Active Record MySQL Adapter \Index Definition
|
|
51
|
+
class IndexDefinition < ActiveRecord::ConnectionAdapters::IndexDefinition # :nodoc:
|
|
52
|
+
attr_accessor :enabled
|
|
53
|
+
|
|
54
|
+
def initialize(*args, **kwargs)
|
|
55
|
+
@enabled = kwargs.key?(:enabled) ? kwargs.delete(:enabled) : true
|
|
56
|
+
super
|
|
57
|
+
end
|
|
52
58
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
def defined_for?(columns = nil, name: nil, unique: nil, valid: nil, include: nil, nulls_not_distinct: nil, enabled: nil, **options)
|
|
60
|
+
super(columns, name:, unique:, valid:, include:, nulls_not_distinct:, **options) &&
|
|
61
|
+
(enabled.nil? || self.enabled == enabled)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def disabled?
|
|
65
|
+
!@enabled
|
|
57
66
|
end
|
|
58
67
|
end
|
|
59
68
|
|
|
@@ -106,6 +115,28 @@ module ActiveRecord
|
|
|
106
115
|
# = Active Record MySQL Adapter \Table
|
|
107
116
|
class Table < ActiveRecord::ConnectionAdapters::Table
|
|
108
117
|
include ColumnMethods
|
|
118
|
+
|
|
119
|
+
# Enables an index to be used by query optimizers.
|
|
120
|
+
#
|
|
121
|
+
# t.enable_index(:email)
|
|
122
|
+
#
|
|
123
|
+
# Note: only supported by MySQL version 8.0.0 and greater, and MariaDB version 10.6.0 and greater.
|
|
124
|
+
#
|
|
125
|
+
# See {connection.enable_index}[rdoc-ref:SchemaStatements#enable_index]
|
|
126
|
+
def enable_index(index_name)
|
|
127
|
+
@base.enable_index(name, index_name)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Disables an index not to be used by query optimizers.
|
|
131
|
+
#
|
|
132
|
+
# t.disable_index(:email)
|
|
133
|
+
#
|
|
134
|
+
# Note: only supported by MySQL version 8.0.0 and greater, and MariaDB version 10.6.0 and greater.
|
|
135
|
+
#
|
|
136
|
+
# See {connection.disable_index}[rdoc-ref:SchemaStatements#disable_index]
|
|
137
|
+
def disable_index(index_name)
|
|
138
|
+
@base.disable_index(name, index_name)
|
|
139
|
+
end
|
|
109
140
|
end
|
|
110
141
|
end
|
|
111
142
|
end
|