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
@@ -3,6 +3,7 @@
|
|
3
3
|
require "active_record/connection_adapters/abstract_adapter"
|
4
4
|
require "active_record/connection_adapters/statement_pool"
|
5
5
|
require "active_record/connection_adapters/mysql/column"
|
6
|
+
require "active_record/connection_adapters/mysql/database_statements"
|
6
7
|
require "active_record/connection_adapters/mysql/explain_pretty_printer"
|
7
8
|
require "active_record/connection_adapters/mysql/quoting"
|
8
9
|
require "active_record/connection_adapters/mysql/schema_creation"
|
@@ -14,6 +15,7 @@ require "active_record/connection_adapters/mysql/type_metadata"
|
|
14
15
|
module ActiveRecord
|
15
16
|
module ConnectionAdapters
|
16
17
|
class AbstractMysqlAdapter < AbstractAdapter
|
18
|
+
include MySQL::DatabaseStatements
|
17
19
|
include MySQL::Quoting
|
18
20
|
include MySQL::SchemaStatements
|
19
21
|
|
@@ -51,8 +53,34 @@ module ActiveRecord
|
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
+
class << self
|
57
|
+
def dbconsole(config, options = {})
|
58
|
+
mysql_config = config.configuration_hash
|
59
|
+
|
60
|
+
args = {
|
61
|
+
host: "--host",
|
62
|
+
port: "--port",
|
63
|
+
socket: "--socket",
|
64
|
+
username: "--user",
|
65
|
+
encoding: "--default-character-set",
|
66
|
+
sslca: "--ssl-ca",
|
67
|
+
sslcert: "--ssl-cert",
|
68
|
+
sslcapath: "--ssl-capath",
|
69
|
+
sslcipher: "--ssl-cipher",
|
70
|
+
sslkey: "--ssl-key",
|
71
|
+
ssl_mode: "--ssl-mode"
|
72
|
+
}.filter_map { |opt, arg| "#{arg}=#{mysql_config[opt]}" if mysql_config[opt] }
|
73
|
+
|
74
|
+
if mysql_config[:password] && options[:include_password]
|
75
|
+
args << "--password=#{mysql_config[:password]}"
|
76
|
+
elsif mysql_config[:password] && !mysql_config[:password].to_s.empty?
|
77
|
+
args << "-p"
|
78
|
+
end
|
79
|
+
|
80
|
+
args << config.database
|
81
|
+
|
82
|
+
find_cmd_and_exec(["mysql", "mysql5"], *args)
|
83
|
+
end
|
56
84
|
end
|
57
85
|
|
58
86
|
def get_database_version # :nodoc:
|
@@ -81,6 +109,10 @@ module ActiveRecord
|
|
81
109
|
true
|
82
110
|
end
|
83
111
|
|
112
|
+
def supports_restart_db_transaction?
|
113
|
+
true
|
114
|
+
end
|
115
|
+
|
84
116
|
def supports_explain?
|
85
117
|
true
|
86
118
|
end
|
@@ -95,7 +127,7 @@ module ActiveRecord
|
|
95
127
|
|
96
128
|
def supports_check_constraints?
|
97
129
|
if mariadb?
|
98
|
-
database_version >= "10.2.
|
130
|
+
database_version >= "10.3.10" || (database_version < "10.3" && database_version >= "10.2.22")
|
99
131
|
else
|
100
132
|
database_version >= "8.0.16"
|
101
133
|
end
|
@@ -190,33 +222,36 @@ module ActiveRecord
|
|
190
222
|
# DATABASE STATEMENTS ======================================
|
191
223
|
#++
|
192
224
|
|
193
|
-
# Executes the SQL statement in the context of this connection.
|
194
|
-
def execute(sql, name = nil, async: false)
|
195
|
-
raw_execute(sql, name, async: async)
|
196
|
-
end
|
197
|
-
|
198
225
|
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
199
226
|
# to write stuff in an abstract way without concerning ourselves about whether it
|
200
227
|
# needs to be explicitly freed or not.
|
201
228
|
def execute_and_free(sql, name = nil, async: false) # :nodoc:
|
202
|
-
|
229
|
+
sql = transform_query(sql)
|
230
|
+
check_if_write_query(sql)
|
231
|
+
|
232
|
+
mark_transaction_written_if_write(sql)
|
233
|
+
yield raw_execute(sql, name, async: async)
|
203
234
|
end
|
204
235
|
|
205
236
|
def begin_db_transaction # :nodoc:
|
206
|
-
|
237
|
+
internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
207
238
|
end
|
208
239
|
|
209
240
|
def begin_isolated_db_transaction(isolation) # :nodoc:
|
210
|
-
|
241
|
+
internal_execute("SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
211
242
|
begin_db_transaction
|
212
243
|
end
|
213
244
|
|
214
245
|
def commit_db_transaction # :nodoc:
|
215
|
-
|
246
|
+
internal_execute("COMMIT", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
216
247
|
end
|
217
248
|
|
218
249
|
def exec_rollback_db_transaction # :nodoc:
|
219
|
-
|
250
|
+
internal_execute("ROLLBACK", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
251
|
+
end
|
252
|
+
|
253
|
+
def exec_restart_db_transaction # :nodoc:
|
254
|
+
internal_execute("ROLLBACK AND CHAIN", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
220
255
|
end
|
221
256
|
|
222
257
|
def empty_insert_statement_value(primary_key = nil) # :nodoc:
|
@@ -296,7 +331,8 @@ module ActiveRecord
|
|
296
331
|
#
|
297
332
|
# Example:
|
298
333
|
# rename_table('octopuses', 'octopi')
|
299
|
-
def rename_table(table_name, new_name)
|
334
|
+
def rename_table(table_name, new_name, **options)
|
335
|
+
validate_table_length!(new_name) unless options[:_uses_legacy_table_name]
|
300
336
|
schema_cache.clear_data_source_cache!(table_name.to_s)
|
301
337
|
schema_cache.clear_data_source_cache!(new_name.to_s)
|
302
338
|
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
@@ -334,11 +370,20 @@ module ActiveRecord
|
|
334
370
|
end
|
335
371
|
|
336
372
|
def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
|
373
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{change_column_default_for_alter(table_name, column_name, default_or_changes)}"
|
374
|
+
end
|
375
|
+
|
376
|
+
def build_change_column_default_definition(table_name, column_name, default_or_changes) # :nodoc:
|
377
|
+
column = column_for(table_name, column_name)
|
378
|
+
return unless column
|
379
|
+
|
337
380
|
default = extract_new_default_value(default_or_changes)
|
338
|
-
|
381
|
+
ChangeColumnDefaultDefinition.new(column, default)
|
339
382
|
end
|
340
383
|
|
341
384
|
def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
|
385
|
+
validate_change_column_null_argument!(null)
|
386
|
+
|
342
387
|
unless null || default.nil?
|
343
388
|
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
344
389
|
end
|
@@ -355,18 +400,60 @@ module ActiveRecord
|
|
355
400
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
|
356
401
|
end
|
357
402
|
|
403
|
+
# Builds a ChangeColumnDefinition object.
|
404
|
+
#
|
405
|
+
# This definition object contains information about the column change that would occur
|
406
|
+
# if the same arguments were passed to #change_column. See #change_column for information about
|
407
|
+
# passing a +table_name+, +column_name+, +type+ and other options that can be passed.
|
408
|
+
def build_change_column_definition(table_name, column_name, type, **options) # :nodoc:
|
409
|
+
column = column_for(table_name, column_name)
|
410
|
+
type ||= column.sql_type
|
411
|
+
|
412
|
+
unless options.key?(:default)
|
413
|
+
options[:default] = column.default
|
414
|
+
end
|
415
|
+
|
416
|
+
unless options.key?(:null)
|
417
|
+
options[:null] = column.null
|
418
|
+
end
|
419
|
+
|
420
|
+
unless options.key?(:comment)
|
421
|
+
options[:comment] = column.comment
|
422
|
+
end
|
423
|
+
|
424
|
+
if options[:collation] == :no_collation
|
425
|
+
options.delete(:collation)
|
426
|
+
else
|
427
|
+
options[:collation] ||= column.collation if text_type?(type)
|
428
|
+
end
|
429
|
+
|
430
|
+
unless options.key?(:auto_increment)
|
431
|
+
options[:auto_increment] = column.auto_increment?
|
432
|
+
end
|
433
|
+
|
434
|
+
td = create_table_definition(table_name)
|
435
|
+
cd = td.new_column_definition(column.name, type, **options)
|
436
|
+
ChangeColumnDefinition.new(cd, column.name)
|
437
|
+
end
|
438
|
+
|
358
439
|
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
359
440
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
|
360
441
|
rename_column_indexes(table_name, column_name, new_column_name)
|
361
442
|
end
|
362
443
|
|
363
444
|
def add_index(table_name, column_name, **options) # :nodoc:
|
445
|
+
create_index = build_create_index_definition(table_name, column_name, **options)
|
446
|
+
return unless create_index
|
447
|
+
|
448
|
+
execute schema_creation.accept(create_index)
|
449
|
+
end
|
450
|
+
|
451
|
+
def build_create_index_definition(table_name, column_name, **options) # :nodoc:
|
364
452
|
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
365
453
|
|
366
454
|
return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
|
367
455
|
|
368
|
-
|
369
|
-
execute schema_creation.accept(create_index)
|
456
|
+
CreateIndexDefinition.new(index, algorithm)
|
370
457
|
end
|
371
458
|
|
372
459
|
def add_sql_comment!(sql, comment) # :nodoc:
|
@@ -379,11 +466,13 @@ module ActiveRecord
|
|
379
466
|
|
380
467
|
scope = quoted_scope(table_name)
|
381
468
|
|
382
|
-
|
469
|
+
# MySQL returns 1 row for each column of composite foreign keys.
|
470
|
+
fk_info = internal_exec_query(<<~SQL, "SCHEMA")
|
383
471
|
SELECT fk.referenced_table_name AS 'to_table',
|
384
472
|
fk.referenced_column_name AS 'primary_key',
|
385
473
|
fk.column_name AS 'column',
|
386
474
|
fk.constraint_name AS 'name',
|
475
|
+
fk.ordinal_position AS 'position',
|
387
476
|
rc.update_rule AS 'on_update',
|
388
477
|
rc.delete_rule AS 'on_delete'
|
389
478
|
FROM information_schema.referential_constraints rc
|
@@ -396,15 +485,22 @@ module ActiveRecord
|
|
396
485
|
AND rc.table_name = #{scope[:name]}
|
397
486
|
SQL
|
398
487
|
|
399
|
-
fk_info.
|
488
|
+
grouped_fk = fk_info.group_by { |row| row["name"] }.values.each { |group| group.sort_by! { |row| row["position"] } }
|
489
|
+
grouped_fk.map do |group|
|
490
|
+
row = group.first
|
400
491
|
options = {
|
401
|
-
column: unquote_identifier(row["column"]),
|
402
492
|
name: row["name"],
|
403
|
-
|
493
|
+
on_update: extract_foreign_key_action(row["on_update"]),
|
494
|
+
on_delete: extract_foreign_key_action(row["on_delete"])
|
404
495
|
}
|
405
496
|
|
406
|
-
|
407
|
-
|
497
|
+
if group.one?
|
498
|
+
options[:column] = unquote_identifier(row["column"])
|
499
|
+
options[:primary_key] = row["primary_key"]
|
500
|
+
else
|
501
|
+
options[:column] = group.map { |row| unquote_identifier(row["column"]) }
|
502
|
+
options[:primary_key] = group.map { |row| row["primary_key"] }
|
503
|
+
end
|
408
504
|
|
409
505
|
ForeignKeyDefinition.new(table_name, unquote_identifier(row["to_table"]), options)
|
410
506
|
end
|
@@ -426,7 +522,7 @@ module ActiveRecord
|
|
426
522
|
SQL
|
427
523
|
sql += " AND cc.table_name = #{scope[:name]}" if mariadb?
|
428
524
|
|
429
|
-
chk_info =
|
525
|
+
chk_info = internal_exec_query(sql, "SCHEMA")
|
430
526
|
|
431
527
|
chk_info.map do |row|
|
432
528
|
options = {
|
@@ -557,15 +653,18 @@ module ActiveRecord
|
|
557
653
|
end
|
558
654
|
|
559
655
|
class << self
|
656
|
+
def extended_type_map(default_timezone: nil, emulate_booleans:) # :nodoc:
|
657
|
+
super(default_timezone: default_timezone).tap do |m|
|
658
|
+
if emulate_booleans
|
659
|
+
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
|
660
|
+
end
|
661
|
+
end
|
662
|
+
end
|
663
|
+
|
560
664
|
private
|
561
665
|
def initialize_type_map(m)
|
562
666
|
super
|
563
667
|
|
564
|
-
m.register_type(%r(char)i) do |sql_type|
|
565
|
-
limit = extract_limit(sql_type)
|
566
|
-
Type.lookup(:string, adapter: :mysql2, limit: limit)
|
567
|
-
end
|
568
|
-
|
569
668
|
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
570
669
|
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
571
670
|
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
|
@@ -585,9 +684,6 @@ module ActiveRecord
|
|
585
684
|
|
586
685
|
m.alias_type %r(year)i, "integer"
|
587
686
|
m.alias_type %r(bit)i, "binary"
|
588
|
-
|
589
|
-
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
|
590
|
-
m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
|
591
687
|
end
|
592
688
|
|
593
689
|
def register_integer_type(mapping, key, **options)
|
@@ -609,10 +705,8 @@ module ActiveRecord
|
|
609
705
|
end
|
610
706
|
end
|
611
707
|
|
612
|
-
|
613
|
-
|
614
|
-
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
|
615
|
-
end
|
708
|
+
EXTENDED_TYPE_MAPS = Concurrent::Map.new
|
709
|
+
EMULATE_BOOLEANS_TRUE = { emulate_booleans: true }.freeze
|
616
710
|
|
617
711
|
private
|
618
712
|
def strip_whitespace_characters(expression)
|
@@ -621,25 +715,36 @@ module ActiveRecord
|
|
621
715
|
expression
|
622
716
|
end
|
623
717
|
|
624
|
-
def
|
625
|
-
|
718
|
+
def extended_type_map_key
|
719
|
+
if @default_timezone
|
720
|
+
{ default_timezone: @default_timezone, emulate_booleans: emulate_booleans }
|
721
|
+
elsif emulate_booleans
|
722
|
+
EMULATE_BOOLEANS_TRUE
|
723
|
+
end
|
626
724
|
end
|
627
725
|
|
628
|
-
def
|
629
|
-
|
630
|
-
end
|
726
|
+
def handle_warnings(sql)
|
727
|
+
return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
|
631
728
|
|
632
|
-
|
633
|
-
|
634
|
-
|
729
|
+
@affected_rows_before_warnings = @raw_connection.affected_rows
|
730
|
+
result = @raw_connection.query("SHOW WARNINGS")
|
731
|
+
result.each do |level, code, message|
|
732
|
+
warning = SQLWarning.new(message, code, level, sql, @pool)
|
733
|
+
next if warning_ignored?(warning)
|
635
734
|
|
636
|
-
|
637
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
638
|
-
@connection.query(sql)
|
639
|
-
end
|
735
|
+
ActiveRecord.db_warnings_action.call(warning)
|
640
736
|
end
|
641
737
|
end
|
642
738
|
|
739
|
+
def warning_ignored?(warning)
|
740
|
+
warning.level == "Note" || super
|
741
|
+
end
|
742
|
+
|
743
|
+
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
744
|
+
# made since we established the connection
|
745
|
+
def sync_timezone_changes(raw_connection)
|
746
|
+
end
|
747
|
+
|
643
748
|
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
|
644
749
|
ER_DB_CREATE_EXISTS = 1007
|
645
750
|
ER_FILSORT_ABORT = 1028
|
@@ -657,77 +762,59 @@ module ActiveRecord
|
|
657
762
|
ER_CANNOT_CREATE_TABLE = 1005
|
658
763
|
ER_LOCK_WAIT_TIMEOUT = 1205
|
659
764
|
ER_QUERY_INTERRUPTED = 1317
|
765
|
+
ER_CONNECTION_KILLED = 1927
|
766
|
+
CR_SERVER_GONE_ERROR = 2006
|
767
|
+
CR_SERVER_LOST = 2013
|
660
768
|
ER_QUERY_TIMEOUT = 3024
|
661
769
|
ER_FK_INCOMPATIBLE_COLUMNS = 3780
|
770
|
+
ER_CLIENT_INTERACTION_TIMEOUT = 4031
|
662
771
|
|
663
772
|
def translate_exception(exception, message:, sql:, binds:)
|
664
773
|
case error_number(exception)
|
665
774
|
when nil
|
666
775
|
if exception.message.match?(/MySQL client is not connected/i)
|
667
|
-
ConnectionNotEstablished.new(exception)
|
776
|
+
ConnectionNotEstablished.new(exception, connection_pool: @pool)
|
668
777
|
else
|
669
778
|
super
|
670
779
|
end
|
780
|
+
when ER_CONNECTION_KILLED, CR_SERVER_GONE_ERROR, CR_SERVER_LOST, ER_CLIENT_INTERACTION_TIMEOUT
|
781
|
+
ConnectionFailed.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
671
782
|
when ER_DB_CREATE_EXISTS
|
672
|
-
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
|
783
|
+
DatabaseAlreadyExists.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
673
784
|
when ER_DUP_ENTRY
|
674
|
-
RecordNotUnique.new(message, sql: sql, binds: binds)
|
785
|
+
RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
675
786
|
when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
|
676
|
-
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
787
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
677
788
|
when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
|
678
|
-
mismatched_foreign_key(message, sql: sql, binds: binds)
|
789
|
+
mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
|
679
790
|
when ER_CANNOT_CREATE_TABLE
|
680
791
|
if message.include?("errno: 150")
|
681
|
-
mismatched_foreign_key(message, sql: sql, binds: binds)
|
792
|
+
mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
|
682
793
|
else
|
683
794
|
super
|
684
795
|
end
|
685
796
|
when ER_DATA_TOO_LONG
|
686
|
-
ValueTooLong.new(message, sql: sql, binds: binds)
|
797
|
+
ValueTooLong.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
687
798
|
when ER_OUT_OF_RANGE
|
688
|
-
RangeError.new(message, sql: sql, binds: binds)
|
799
|
+
RangeError.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
689
800
|
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
690
|
-
NotNullViolation.new(message, sql: sql, binds: binds)
|
801
|
+
NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
691
802
|
when ER_LOCK_DEADLOCK
|
692
|
-
Deadlocked.new(message, sql: sql, binds: binds)
|
803
|
+
Deadlocked.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
693
804
|
when ER_LOCK_WAIT_TIMEOUT
|
694
|
-
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
805
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
695
806
|
when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
|
696
|
-
StatementTimeout.new(message, sql: sql, binds: binds)
|
807
|
+
StatementTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
697
808
|
when ER_QUERY_INTERRUPTED
|
698
|
-
QueryCanceled.new(message, sql: sql, binds: binds)
|
809
|
+
QueryCanceled.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
699
810
|
else
|
700
811
|
super
|
701
812
|
end
|
702
813
|
end
|
703
814
|
|
704
815
|
def change_column_for_alter(table_name, column_name, type, **options)
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
unless options.key?(:default)
|
709
|
-
options[:default] = column.default
|
710
|
-
end
|
711
|
-
|
712
|
-
unless options.key?(:null)
|
713
|
-
options[:null] = column.null
|
714
|
-
end
|
715
|
-
|
716
|
-
unless options.key?(:comment)
|
717
|
-
options[:comment] = column.comment
|
718
|
-
end
|
719
|
-
|
720
|
-
unless options.key?(:collation)
|
721
|
-
options[:collation] = column.collation if text_type?(type)
|
722
|
-
end
|
723
|
-
|
724
|
-
unless options.key?(:auto_increment)
|
725
|
-
options[:auto_increment] = column.auto_increment?
|
726
|
-
end
|
727
|
-
|
728
|
-
td = create_table_definition(table_name)
|
729
|
-
cd = td.new_column_definition(column.name, type, **options)
|
730
|
-
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
816
|
+
cd = build_change_column_definition(table_name, column_name, type, **options)
|
817
|
+
schema_creation.accept(cd)
|
731
818
|
end
|
732
819
|
|
733
820
|
def rename_column_for_alter(table_name, column_name, new_column_name)
|
@@ -741,7 +828,7 @@ module ActiveRecord
|
|
741
828
|
comment: column.comment
|
742
829
|
}
|
743
830
|
|
744
|
-
current_type =
|
831
|
+
current_type = internal_exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
|
745
832
|
td = create_table_definition(table_name)
|
746
833
|
cd = td.new_column_definition(new_column_name, current_type, **options)
|
747
834
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
@@ -778,9 +865,6 @@ module ActiveRecord
|
|
778
865
|
def configure_connection
|
779
866
|
variables = @config.fetch(:variables, {}).stringify_keys
|
780
867
|
|
781
|
-
# By default, MySQL 'where id is null' selects the last inserted id; Turn this off.
|
782
|
-
variables["sql_auto_is_null"] = 0
|
783
|
-
|
784
868
|
# Increase timeout so the server doesn't disconnect us.
|
785
869
|
wait_timeout = self.class.type_cast_config_to_integer(@config[:wait_timeout])
|
786
870
|
wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
|
@@ -824,7 +908,7 @@ module ActiveRecord
|
|
824
908
|
end.join(", ")
|
825
909
|
|
826
910
|
# ...and send them all in one query
|
827
|
-
|
911
|
+
internal_execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}")
|
828
912
|
end
|
829
913
|
|
830
914
|
def column_definitions(table_name) # :nodoc:
|
@@ -834,7 +918,7 @@ module ActiveRecord
|
|
834
918
|
end
|
835
919
|
|
836
920
|
def create_table_info(table_name) # :nodoc:
|
837
|
-
|
921
|
+
internal_exec_query("SHOW CREATE TABLE #{quote_table_name(table_name)}", "SCHEMA").first["Create Table"]
|
838
922
|
end
|
839
923
|
|
840
924
|
def arel_visitor
|
@@ -845,18 +929,17 @@ module ActiveRecord
|
|
845
929
|
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
846
930
|
end
|
847
931
|
|
848
|
-
def
|
932
|
+
def mismatched_foreign_key_details(message:, sql:)
|
933
|
+
foreign_key_pat =
|
934
|
+
/Referencing column '(\w+)' and referenced/i =~ message ? $1 : '\w+'
|
935
|
+
|
849
936
|
match = %r/
|
850
937
|
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
851
|
-
FOREIGN\s+KEY\s*\(`?(?<foreign_key
|
938
|
+
FOREIGN\s+KEY\s*\(`?(?<foreign_key>#{foreign_key_pat})`?\)\s*
|
852
939
|
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
853
940
|
/xmi.match(sql)
|
854
941
|
|
855
|
-
options = {
|
856
|
-
message: message,
|
857
|
-
sql: sql,
|
858
|
-
binds: binds,
|
859
|
-
}
|
942
|
+
options = {}
|
860
943
|
|
861
944
|
if match
|
862
945
|
options[:table] = match[:table]
|
@@ -866,20 +949,29 @@ module ActiveRecord
|
|
866
949
|
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
867
950
|
end
|
868
951
|
|
952
|
+
options
|
953
|
+
end
|
954
|
+
|
955
|
+
def mismatched_foreign_key(message, sql:, binds:, connection_pool:)
|
956
|
+
options = {
|
957
|
+
message: message,
|
958
|
+
sql: sql,
|
959
|
+
binds: binds,
|
960
|
+
connection_pool: connection_pool
|
961
|
+
}
|
962
|
+
|
963
|
+
if sql
|
964
|
+
options.update mismatched_foreign_key_details(message: message, sql: sql)
|
965
|
+
else
|
966
|
+
options[:query_parser] = ->(sql) { mismatched_foreign_key_details(message: message, sql: sql) }
|
967
|
+
end
|
968
|
+
|
869
969
|
MismatchedForeignKey.new(**options)
|
870
970
|
end
|
871
971
|
|
872
972
|
def version_string(full_version_string)
|
873
973
|
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
874
974
|
end
|
875
|
-
|
876
|
-
ActiveRecord::Type.register(:immutable_string, adapter: :mysql2) do |_, **args|
|
877
|
-
Type::ImmutableString.new(true: "1", false: "0", **args)
|
878
|
-
end
|
879
|
-
ActiveRecord::Type.register(:string, adapter: :mysql2) do |_, **args|
|
880
|
-
Type::String.new(true: "1", false: "0", **args)
|
881
|
-
end
|
882
|
-
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
|
883
975
|
end
|
884
976
|
end
|
885
977
|
end
|
@@ -63,6 +63,15 @@ module ActiveRecord
|
|
63
63
|
coder["comment"] = @comment
|
64
64
|
end
|
65
65
|
|
66
|
+
# whether the column is auto-populated by the database using a sequence
|
67
|
+
def auto_incremented_by_db?
|
68
|
+
false
|
69
|
+
end
|
70
|
+
|
71
|
+
def auto_populated?
|
72
|
+
auto_incremented_by_db? || default_function
|
73
|
+
end
|
74
|
+
|
66
75
|
def ==(other)
|
67
76
|
other.is_a?(Column) &&
|
68
77
|
name == other.name &&
|