activerecord 7.0.4 → 7.1.5.1
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 +1971 -1243
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +20 -4
- 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 +20 -14
- data/lib/active_record/associations/collection_proxy.rb +20 -10
- 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/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/preloader/association.rb +31 -7
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +13 -10
- 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 +333 -222
- 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 +53 -35
- 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 +21 -8
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -4
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +148 -26
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +59 -10
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +16 -32
- 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 +80 -50
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +129 -31
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +62 -23
- data/lib/active_record/connection_adapters/abstract/quoting.rb +51 -7
- 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 +155 -25
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +297 -127
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +509 -103
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +254 -125
- 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 +23 -144
- data/lib/active_record/connection_adapters/mysql/quoting.rb +29 -14
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +19 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +106 -55
- 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 +16 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -45
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +41 -8
- 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 +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +365 -61
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +354 -193
- 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 +52 -39
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +9 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +213 -85
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +72 -95
- data/lib/active_record/core.rb +181 -154
- data/lib/active_record/counter_cache.rb +52 -27
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +28 -14
- 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 +15 -10
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/disable_joins_association_relation.rb +1 -1
- 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 +42 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +23 -8
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- 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 +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +112 -28
- data/lib/active_record/errors.rb +112 -18
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_subscriber.rb +1 -1
- 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 +135 -71
- data/lib/active_record/future_result.rb +40 -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 +57 -10
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +120 -30
- data/lib/active_record/locking/optimistic.rb +33 -19
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- data/lib/active_record/marshalling.rb +59 -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 +9 -11
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +105 -7
- data/lib/active_record/migration/compatibility.rb +163 -58
- 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/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +271 -114
- data/lib/active_record/model_schema.rb +69 -44
- data/lib/active_record/nested_attributes.rb +37 -8
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +195 -42
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- data/lib/active_record/query_logs.rb +87 -51
- 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 +14 -9
- data/lib/active_record/railties/databases.rake +144 -150
- 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 +189 -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 +232 -81
- data/lib/active_record/relation/delegation.rb +23 -9
- data/lib/active_record/relation/finder_methods.rb +77 -16
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- 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 +25 -1
- data/lib/active_record/relation/query_methods.rb +408 -76
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +103 -37
- data/lib/active_record/result.rb +25 -9
- data/lib/active_record/runtime_registry.rb +24 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +50 -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 +9 -9
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +152 -108
- 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 +15 -7
- data/lib/active_record/test_fixtures.rb +114 -96
- data/lib/active_record/timestamp.rb +30 -16
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +39 -13
- 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/serialized.rb +8 -4
- 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 +130 -17
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +1 -1
- data/lib/arel/nodes/and.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/filter.rb +1 -1
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- 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/tree_manager.rb +5 -1
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +83 -18
- 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 +51 -15
- 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
|
@@ -138,11 +170,6 @@ module ActiveRecord
|
|
138
170
|
true
|
139
171
|
end
|
140
172
|
|
141
|
-
def field_ordered_value(column, values) # :nodoc:
|
142
|
-
field = Arel::Nodes::NamedFunction.new("FIELD", [column, values.reverse.map { |value| Arel::Nodes.build_quoted(value) }])
|
143
|
-
Arel::Nodes::Descending.new(field)
|
144
|
-
end
|
145
|
-
|
146
173
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
147
174
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
148
175
|
end
|
@@ -195,33 +222,36 @@ module ActiveRecord
|
|
195
222
|
# DATABASE STATEMENTS ======================================
|
196
223
|
#++
|
197
224
|
|
198
|
-
# Executes the SQL statement in the context of this connection.
|
199
|
-
def execute(sql, name = nil, async: false)
|
200
|
-
raw_execute(sql, name, async: async)
|
201
|
-
end
|
202
|
-
|
203
225
|
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
204
226
|
# to write stuff in an abstract way without concerning ourselves about whether it
|
205
227
|
# needs to be explicitly freed or not.
|
206
228
|
def execute_and_free(sql, name = nil, async: false) # :nodoc:
|
207
|
-
|
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)
|
208
234
|
end
|
209
235
|
|
210
236
|
def begin_db_transaction # :nodoc:
|
211
|
-
|
237
|
+
internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
212
238
|
end
|
213
239
|
|
214
240
|
def begin_isolated_db_transaction(isolation) # :nodoc:
|
215
|
-
|
241
|
+
internal_execute("SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
216
242
|
begin_db_transaction
|
217
243
|
end
|
218
244
|
|
219
245
|
def commit_db_transaction # :nodoc:
|
220
|
-
|
246
|
+
internal_execute("COMMIT", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
221
247
|
end
|
222
248
|
|
223
249
|
def exec_rollback_db_transaction # :nodoc:
|
224
|
-
|
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)
|
225
255
|
end
|
226
256
|
|
227
257
|
def empty_insert_statement_value(primary_key = nil) # :nodoc:
|
@@ -301,11 +331,12 @@ module ActiveRecord
|
|
301
331
|
#
|
302
332
|
# Example:
|
303
333
|
# rename_table('octopuses', 'octopi')
|
304
|
-
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]
|
305
336
|
schema_cache.clear_data_source_cache!(table_name.to_s)
|
306
337
|
schema_cache.clear_data_source_cache!(new_name.to_s)
|
307
338
|
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
308
|
-
rename_table_indexes(table_name, new_name)
|
339
|
+
rename_table_indexes(table_name, new_name, **options)
|
309
340
|
end
|
310
341
|
|
311
342
|
# Drops a table from the database.
|
@@ -339,11 +370,20 @@ module ActiveRecord
|
|
339
370
|
end
|
340
371
|
|
341
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
|
+
|
342
380
|
default = extract_new_default_value(default_or_changes)
|
343
|
-
|
381
|
+
ChangeColumnDefaultDefinition.new(column, default)
|
344
382
|
end
|
345
383
|
|
346
384
|
def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
|
385
|
+
validate_change_column_null_argument!(null)
|
386
|
+
|
347
387
|
unless null || default.nil?
|
348
388
|
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
349
389
|
end
|
@@ -360,18 +400,60 @@ module ActiveRecord
|
|
360
400
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
|
361
401
|
end
|
362
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
|
+
|
363
439
|
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
364
440
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
|
365
441
|
rename_column_indexes(table_name, column_name, new_column_name)
|
366
442
|
end
|
367
443
|
|
368
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:
|
369
452
|
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
370
453
|
|
371
454
|
return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
|
372
455
|
|
373
|
-
|
374
|
-
execute schema_creation.accept(create_index)
|
456
|
+
CreateIndexDefinition.new(index, algorithm)
|
375
457
|
end
|
376
458
|
|
377
459
|
def add_sql_comment!(sql, comment) # :nodoc:
|
@@ -384,11 +466,13 @@ module ActiveRecord
|
|
384
466
|
|
385
467
|
scope = quoted_scope(table_name)
|
386
468
|
|
387
|
-
|
469
|
+
# MySQL returns 1 row for each column of composite foreign keys.
|
470
|
+
fk_info = internal_exec_query(<<~SQL, "SCHEMA")
|
388
471
|
SELECT fk.referenced_table_name AS 'to_table',
|
389
472
|
fk.referenced_column_name AS 'primary_key',
|
390
473
|
fk.column_name AS 'column',
|
391
474
|
fk.constraint_name AS 'name',
|
475
|
+
fk.ordinal_position AS 'position',
|
392
476
|
rc.update_rule AS 'on_update',
|
393
477
|
rc.delete_rule AS 'on_delete'
|
394
478
|
FROM information_schema.referential_constraints rc
|
@@ -401,17 +485,24 @@ module ActiveRecord
|
|
401
485
|
AND rc.table_name = #{scope[:name]}
|
402
486
|
SQL
|
403
487
|
|
404
|
-
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
|
405
491
|
options = {
|
406
|
-
column: row["column"],
|
407
492
|
name: row["name"],
|
408
|
-
|
493
|
+
on_update: extract_foreign_key_action(row["on_update"]),
|
494
|
+
on_delete: extract_foreign_key_action(row["on_delete"])
|
409
495
|
}
|
410
496
|
|
411
|
-
|
412
|
-
|
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
|
413
504
|
|
414
|
-
ForeignKeyDefinition.new(table_name, row["to_table"], options)
|
505
|
+
ForeignKeyDefinition.new(table_name, unquote_identifier(row["to_table"]), options)
|
415
506
|
end
|
416
507
|
end
|
417
508
|
|
@@ -431,14 +522,22 @@ module ActiveRecord
|
|
431
522
|
SQL
|
432
523
|
sql += " AND cc.table_name = #{scope[:name]}" if mariadb?
|
433
524
|
|
434
|
-
chk_info =
|
525
|
+
chk_info = internal_exec_query(sql, "SCHEMA")
|
435
526
|
|
436
527
|
chk_info.map do |row|
|
437
528
|
options = {
|
438
529
|
name: row["name"]
|
439
530
|
}
|
440
531
|
expression = row["expression"]
|
441
|
-
expression = expression[1..-2]
|
532
|
+
expression = expression[1..-2] if expression.start_with?("(") && expression.end_with?(")")
|
533
|
+
expression = strip_whitespace_characters(expression)
|
534
|
+
|
535
|
+
unless mariadb?
|
536
|
+
# MySQL returns check constraints expression in an already escaped form.
|
537
|
+
# This leads to duplicate escaping later (e.g. when the expression is used in the SchemaDumper).
|
538
|
+
expression = expression.gsub("\\'", "'")
|
539
|
+
end
|
540
|
+
|
442
541
|
CheckConstraintDefinition.new(table_name, expression, options)
|
443
542
|
end
|
444
543
|
else
|
@@ -536,18 +635,38 @@ module ActiveRecord
|
|
536
635
|
end
|
537
636
|
|
538
637
|
def build_insert_sql(insert) # :nodoc:
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
sql
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
638
|
+
no_op_column = quote_column_name(insert.keys.first)
|
639
|
+
|
640
|
+
# MySQL 8.0.19 replaces `VALUES(<expression>)` clauses with row and column alias names, see https://dev.mysql.com/worklog/task/?id=6312 .
|
641
|
+
# then MySQL 8.0.20 deprecates the `VALUES(<expression>)` see https://dev.mysql.com/worklog/task/?id=13325 .
|
642
|
+
if supports_insert_raw_alias_syntax?
|
643
|
+
values_alias = quote_table_name("#{insert.model.table_name}_values")
|
644
|
+
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"
|
645
|
+
|
646
|
+
if insert.skip_duplicates?
|
647
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{values_alias}.#{no_op_column}"
|
648
|
+
elsif insert.update_duplicates?
|
649
|
+
if insert.raw_update_sql?
|
650
|
+
sql = +"INSERT #{insert.into} #{insert.values_list} ON DUPLICATE KEY UPDATE #{insert.raw_update_sql}"
|
651
|
+
else
|
652
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
653
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column}<=>#{values_alias}.#{column}" }
|
654
|
+
sql << insert.updatable_columns.map { |column| "#{column}=#{values_alias}.#{column}" }.join(",")
|
655
|
+
end
|
656
|
+
end
|
657
|
+
else
|
658
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
659
|
+
|
660
|
+
if insert.skip_duplicates?
|
661
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
662
|
+
elsif insert.update_duplicates?
|
663
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
664
|
+
if insert.raw_update_sql?
|
665
|
+
sql << insert.raw_update_sql
|
666
|
+
else
|
667
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
|
668
|
+
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
669
|
+
end
|
551
670
|
end
|
552
671
|
end
|
553
672
|
|
@@ -561,15 +680,18 @@ module ActiveRecord
|
|
561
680
|
end
|
562
681
|
|
563
682
|
class << self
|
683
|
+
def extended_type_map(default_timezone: nil, emulate_booleans:) # :nodoc:
|
684
|
+
super(default_timezone: default_timezone).tap do |m|
|
685
|
+
if emulate_booleans
|
686
|
+
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
|
687
|
+
end
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
564
691
|
private
|
565
692
|
def initialize_type_map(m)
|
566
693
|
super
|
567
694
|
|
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
695
|
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
574
696
|
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
575
697
|
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
|
@@ -589,9 +711,6 @@ module ActiveRecord
|
|
589
711
|
|
590
712
|
m.alias_type %r(year)i, "integer"
|
591
713
|
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)
|
595
714
|
end
|
596
715
|
|
597
716
|
def register_integer_type(mapping, key, **options)
|
@@ -613,27 +732,46 @@ module ActiveRecord
|
|
613
732
|
end
|
614
733
|
end
|
615
734
|
|
616
|
-
|
617
|
-
|
618
|
-
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
|
619
|
-
end
|
735
|
+
EXTENDED_TYPE_MAPS = Concurrent::Map.new
|
736
|
+
EMULATE_BOOLEANS_TRUE = { emulate_booleans: true }.freeze
|
620
737
|
|
621
738
|
private
|
622
|
-
def
|
623
|
-
|
739
|
+
def strip_whitespace_characters(expression)
|
740
|
+
expression = expression.gsub(/\\n|\\\\/, "")
|
741
|
+
expression = expression.gsub(/\s{2,}/, " ")
|
742
|
+
expression
|
624
743
|
end
|
625
744
|
|
626
|
-
def
|
627
|
-
|
628
|
-
|
745
|
+
def extended_type_map_key
|
746
|
+
if @default_timezone
|
747
|
+
{ default_timezone: @default_timezone, emulate_booleans: emulate_booleans }
|
748
|
+
elsif emulate_booleans
|
749
|
+
EMULATE_BOOLEANS_TRUE
|
750
|
+
end
|
751
|
+
end
|
629
752
|
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
753
|
+
def handle_warnings(sql)
|
754
|
+
return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
|
755
|
+
|
756
|
+
@affected_rows_before_warnings = @raw_connection.affected_rows
|
757
|
+
result = @raw_connection.query("SHOW WARNINGS")
|
758
|
+
result.each do |level, code, message|
|
759
|
+
warning = SQLWarning.new(message, code, level, sql, @pool)
|
760
|
+
next if warning_ignored?(warning)
|
761
|
+
|
762
|
+
ActiveRecord.db_warnings_action.call(warning)
|
634
763
|
end
|
635
764
|
end
|
636
765
|
|
766
|
+
def warning_ignored?(warning)
|
767
|
+
warning.level == "Note" || super
|
768
|
+
end
|
769
|
+
|
770
|
+
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
771
|
+
# made since we established the connection
|
772
|
+
def sync_timezone_changes(raw_connection)
|
773
|
+
end
|
774
|
+
|
637
775
|
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
|
638
776
|
ER_DB_CREATE_EXISTS = 1007
|
639
777
|
ER_FILSORT_ABORT = 1028
|
@@ -651,77 +789,59 @@ module ActiveRecord
|
|
651
789
|
ER_CANNOT_CREATE_TABLE = 1005
|
652
790
|
ER_LOCK_WAIT_TIMEOUT = 1205
|
653
791
|
ER_QUERY_INTERRUPTED = 1317
|
792
|
+
ER_CONNECTION_KILLED = 1927
|
793
|
+
CR_SERVER_GONE_ERROR = 2006
|
794
|
+
CR_SERVER_LOST = 2013
|
654
795
|
ER_QUERY_TIMEOUT = 3024
|
655
796
|
ER_FK_INCOMPATIBLE_COLUMNS = 3780
|
797
|
+
ER_CLIENT_INTERACTION_TIMEOUT = 4031
|
656
798
|
|
657
799
|
def translate_exception(exception, message:, sql:, binds:)
|
658
800
|
case error_number(exception)
|
659
801
|
when nil
|
660
802
|
if exception.message.match?(/MySQL client is not connected/i)
|
661
|
-
ConnectionNotEstablished.new(exception)
|
803
|
+
ConnectionNotEstablished.new(exception, connection_pool: @pool)
|
662
804
|
else
|
663
805
|
super
|
664
806
|
end
|
807
|
+
when ER_CONNECTION_KILLED, CR_SERVER_GONE_ERROR, CR_SERVER_LOST, ER_CLIENT_INTERACTION_TIMEOUT
|
808
|
+
ConnectionFailed.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
665
809
|
when ER_DB_CREATE_EXISTS
|
666
|
-
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
|
810
|
+
DatabaseAlreadyExists.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
667
811
|
when ER_DUP_ENTRY
|
668
|
-
RecordNotUnique.new(message, sql: sql, binds: binds)
|
812
|
+
RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
669
813
|
when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
|
670
|
-
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
814
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
671
815
|
when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
|
672
|
-
mismatched_foreign_key(message, sql: sql, binds: binds)
|
816
|
+
mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
|
673
817
|
when ER_CANNOT_CREATE_TABLE
|
674
818
|
if message.include?("errno: 150")
|
675
|
-
mismatched_foreign_key(message, sql: sql, binds: binds)
|
819
|
+
mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
|
676
820
|
else
|
677
821
|
super
|
678
822
|
end
|
679
823
|
when ER_DATA_TOO_LONG
|
680
|
-
ValueTooLong.new(message, sql: sql, binds: binds)
|
824
|
+
ValueTooLong.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
681
825
|
when ER_OUT_OF_RANGE
|
682
|
-
RangeError.new(message, sql: sql, binds: binds)
|
826
|
+
RangeError.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
683
827
|
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
684
|
-
NotNullViolation.new(message, sql: sql, binds: binds)
|
828
|
+
NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
685
829
|
when ER_LOCK_DEADLOCK
|
686
|
-
Deadlocked.new(message, sql: sql, binds: binds)
|
830
|
+
Deadlocked.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
687
831
|
when ER_LOCK_WAIT_TIMEOUT
|
688
|
-
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
832
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
689
833
|
when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
|
690
|
-
StatementTimeout.new(message, sql: sql, binds: binds)
|
834
|
+
StatementTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
691
835
|
when ER_QUERY_INTERRUPTED
|
692
|
-
QueryCanceled.new(message, sql: sql, binds: binds)
|
836
|
+
QueryCanceled.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
693
837
|
else
|
694
838
|
super
|
695
839
|
end
|
696
840
|
end
|
697
841
|
|
698
842
|
def change_column_for_alter(table_name, column_name, type, **options)
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
unless options.key?(:default)
|
703
|
-
options[:default] = column.default
|
704
|
-
end
|
705
|
-
|
706
|
-
unless options.key?(:null)
|
707
|
-
options[:null] = column.null
|
708
|
-
end
|
709
|
-
|
710
|
-
unless options.key?(:comment)
|
711
|
-
options[:comment] = column.comment
|
712
|
-
end
|
713
|
-
|
714
|
-
unless options.key?(:collation)
|
715
|
-
options[:collation] = column.collation
|
716
|
-
end
|
717
|
-
|
718
|
-
unless options.key?(:auto_increment)
|
719
|
-
options[:auto_increment] = column.auto_increment?
|
720
|
-
end
|
721
|
-
|
722
|
-
td = create_table_definition(table_name)
|
723
|
-
cd = td.new_column_definition(column.name, type, **options)
|
724
|
-
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
843
|
+
cd = build_change_column_definition(table_name, column_name, type, **options)
|
844
|
+
schema_creation.accept(cd)
|
725
845
|
end
|
726
846
|
|
727
847
|
def rename_column_for_alter(table_name, column_name, new_column_name)
|
@@ -735,7 +855,7 @@ module ActiveRecord
|
|
735
855
|
comment: column.comment
|
736
856
|
}
|
737
857
|
|
738
|
-
current_type =
|
858
|
+
current_type = internal_exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
|
739
859
|
td = create_table_definition(table_name)
|
740
860
|
cd = td.new_column_definition(new_column_name, current_type, **options)
|
741
861
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
@@ -753,6 +873,10 @@ module ActiveRecord
|
|
753
873
|
"DROP INDEX #{quote_column_name(index_name)}"
|
754
874
|
end
|
755
875
|
|
876
|
+
def supports_insert_raw_alias_syntax?
|
877
|
+
!mariadb? && database_version >= "8.0.19"
|
878
|
+
end
|
879
|
+
|
756
880
|
def supports_rename_index?
|
757
881
|
if mariadb?
|
758
882
|
database_version >= "10.5.2"
|
@@ -772,9 +896,6 @@ module ActiveRecord
|
|
772
896
|
def configure_connection
|
773
897
|
variables = @config.fetch(:variables, {}).stringify_keys
|
774
898
|
|
775
|
-
# By default, MySQL 'where id is null' selects the last inserted id; Turn this off.
|
776
|
-
variables["sql_auto_is_null"] = 0
|
777
|
-
|
778
899
|
# Increase timeout so the server doesn't disconnect us.
|
779
900
|
wait_timeout = self.class.type_cast_config_to_integer(@config[:wait_timeout])
|
780
901
|
wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
|
@@ -818,7 +939,7 @@ module ActiveRecord
|
|
818
939
|
end.join(", ")
|
819
940
|
|
820
941
|
# ...and send them all in one query
|
821
|
-
|
942
|
+
internal_execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}")
|
822
943
|
end
|
823
944
|
|
824
945
|
def column_definitions(table_name) # :nodoc:
|
@@ -828,7 +949,7 @@ module ActiveRecord
|
|
828
949
|
end
|
829
950
|
|
830
951
|
def create_table_info(table_name) # :nodoc:
|
831
|
-
|
952
|
+
internal_exec_query("SHOW CREATE TABLE #{quote_table_name(table_name)}", "SCHEMA").first["Create Table"]
|
832
953
|
end
|
833
954
|
|
834
955
|
def arel_visitor
|
@@ -839,18 +960,17 @@ module ActiveRecord
|
|
839
960
|
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
840
961
|
end
|
841
962
|
|
842
|
-
def
|
963
|
+
def mismatched_foreign_key_details(message:, sql:)
|
964
|
+
foreign_key_pat =
|
965
|
+
/Referencing column '(\w+)' and referenced/i =~ message ? $1 : '\w+'
|
966
|
+
|
843
967
|
match = %r/
|
844
968
|
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
845
|
-
FOREIGN\s+KEY\s*\(`?(?<foreign_key
|
969
|
+
FOREIGN\s+KEY\s*\(`?(?<foreign_key>#{foreign_key_pat})`?\)\s*
|
846
970
|
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
847
971
|
/xmi.match(sql)
|
848
972
|
|
849
|
-
options = {
|
850
|
-
message: message,
|
851
|
-
sql: sql,
|
852
|
-
binds: binds,
|
853
|
-
}
|
973
|
+
options = {}
|
854
974
|
|
855
975
|
if match
|
856
976
|
options[:table] = match[:table]
|
@@ -860,20 +980,29 @@ module ActiveRecord
|
|
860
980
|
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
861
981
|
end
|
862
982
|
|
983
|
+
options
|
984
|
+
end
|
985
|
+
|
986
|
+
def mismatched_foreign_key(message, sql:, binds:, connection_pool:)
|
987
|
+
options = {
|
988
|
+
message: message,
|
989
|
+
sql: sql,
|
990
|
+
binds: binds,
|
991
|
+
connection_pool: connection_pool
|
992
|
+
}
|
993
|
+
|
994
|
+
if sql
|
995
|
+
options.update mismatched_foreign_key_details(message: message, sql: sql)
|
996
|
+
else
|
997
|
+
options[:query_parser] = ->(sql) { mismatched_foreign_key_details(message: message, sql: sql) }
|
998
|
+
end
|
999
|
+
|
863
1000
|
MismatchedForeignKey.new(**options)
|
864
1001
|
end
|
865
1002
|
|
866
1003
|
def version_string(full_version_string)
|
867
1004
|
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
868
1005
|
end
|
869
|
-
|
870
|
-
ActiveRecord::Type.register(:immutable_string, adapter: :mysql2) do |_, **args|
|
871
|
-
Type::ImmutableString.new(true: "1", false: "0", **args)
|
872
|
-
end
|
873
|
-
ActiveRecord::Type.register(:string, adapter: :mysql2) do |_, **args|
|
874
|
-
Type::String.new(true: "1", false: "0", **args)
|
875
|
-
end
|
876
|
-
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
|
877
1006
|
end
|
878
1007
|
end
|
879
1008
|
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 &&
|