activerecord 7.0.8.7 → 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 +1795 -1424
- data/MIT-LICENSE +1 -1
- data/README.rdoc +16 -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 +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 +19 -13
- data/lib/active_record/associations/collection_proxy.rb +15 -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.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 +319 -217
- 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 -0
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +145 -21
- 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 +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 +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 +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 +296 -127
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +511 -92
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +244 -121
- 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 +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 +14 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +74 -40
- 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 +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +10 -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 +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +364 -61
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +353 -192
- 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 +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 +211 -81
- 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/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/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 +1 -1
- 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 +6 -8
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +104 -5
- data/lib/active_record/migration/compatibility.rb +145 -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/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +219 -111
- 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 +188 -37
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- 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 +12 -6
- 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 +181 -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 +187 -63
- 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 +11 -2
- 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 +2 -1
- data/lib/active_record/relation/query_methods.rb +371 -68
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +103 -37
- data/lib/active_record/result.rb +19 -5
- 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 +46 -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 +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 +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 +122 -17
- 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 +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 +46 -10
- 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,11 +331,12 @@ 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)}"
|
303
|
-
rename_table_indexes(table_name, new_name)
|
339
|
+
rename_table_indexes(table_name, new_name, **options)
|
304
340
|
end
|
305
341
|
|
306
342
|
# Drops a table from the database.
|
@@ -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 = {
|
@@ -435,6 +531,13 @@ module ActiveRecord
|
|
435
531
|
expression = row["expression"]
|
436
532
|
expression = expression[1..-2] if expression.start_with?("(") && expression.end_with?(")")
|
437
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
|
+
|
438
541
|
CheckConstraintDefinition.new(table_name, expression, options)
|
439
542
|
end
|
440
543
|
else
|
@@ -532,18 +635,38 @@ module ActiveRecord
|
|
532
635
|
end
|
533
636
|
|
534
637
|
def build_insert_sql(insert) # :nodoc:
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
sql
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
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
|
547
670
|
end
|
548
671
|
end
|
549
672
|
|
@@ -557,15 +680,18 @@ module ActiveRecord
|
|
557
680
|
end
|
558
681
|
|
559
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
|
+
|
560
691
|
private
|
561
692
|
def initialize_type_map(m)
|
562
693
|
super
|
563
694
|
|
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
695
|
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
570
696
|
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
571
697
|
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
|
@@ -585,9 +711,6 @@ module ActiveRecord
|
|
585
711
|
|
586
712
|
m.alias_type %r(year)i, "integer"
|
587
713
|
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
714
|
end
|
592
715
|
|
593
716
|
def register_integer_type(mapping, key, **options)
|
@@ -609,10 +732,8 @@ module ActiveRecord
|
|
609
732
|
end
|
610
733
|
end
|
611
734
|
|
612
|
-
|
613
|
-
|
614
|
-
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
|
615
|
-
end
|
735
|
+
EXTENDED_TYPE_MAPS = Concurrent::Map.new
|
736
|
+
EMULATE_BOOLEANS_TRUE = { emulate_booleans: true }.freeze
|
616
737
|
|
617
738
|
private
|
618
739
|
def strip_whitespace_characters(expression)
|
@@ -621,25 +742,36 @@ module ActiveRecord
|
|
621
742
|
expression
|
622
743
|
end
|
623
744
|
|
624
|
-
def
|
625
|
-
|
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
|
626
751
|
end
|
627
752
|
|
628
|
-
def
|
629
|
-
|
630
|
-
end
|
753
|
+
def handle_warnings(sql)
|
754
|
+
return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
|
631
755
|
|
632
|
-
|
633
|
-
|
634
|
-
|
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)
|
635
761
|
|
636
|
-
|
637
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
638
|
-
@connection.query(sql)
|
639
|
-
end
|
762
|
+
ActiveRecord.db_warnings_action.call(warning)
|
640
763
|
end
|
641
764
|
end
|
642
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
|
+
|
643
775
|
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
|
644
776
|
ER_DB_CREATE_EXISTS = 1007
|
645
777
|
ER_FILSORT_ABORT = 1028
|
@@ -657,77 +789,59 @@ module ActiveRecord
|
|
657
789
|
ER_CANNOT_CREATE_TABLE = 1005
|
658
790
|
ER_LOCK_WAIT_TIMEOUT = 1205
|
659
791
|
ER_QUERY_INTERRUPTED = 1317
|
792
|
+
ER_CONNECTION_KILLED = 1927
|
793
|
+
CR_SERVER_GONE_ERROR = 2006
|
794
|
+
CR_SERVER_LOST = 2013
|
660
795
|
ER_QUERY_TIMEOUT = 3024
|
661
796
|
ER_FK_INCOMPATIBLE_COLUMNS = 3780
|
797
|
+
ER_CLIENT_INTERACTION_TIMEOUT = 4031
|
662
798
|
|
663
799
|
def translate_exception(exception, message:, sql:, binds:)
|
664
800
|
case error_number(exception)
|
665
801
|
when nil
|
666
802
|
if exception.message.match?(/MySQL client is not connected/i)
|
667
|
-
ConnectionNotEstablished.new(exception)
|
803
|
+
ConnectionNotEstablished.new(exception, connection_pool: @pool)
|
668
804
|
else
|
669
805
|
super
|
670
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)
|
671
809
|
when ER_DB_CREATE_EXISTS
|
672
|
-
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
|
810
|
+
DatabaseAlreadyExists.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
673
811
|
when ER_DUP_ENTRY
|
674
|
-
RecordNotUnique.new(message, sql: sql, binds: binds)
|
812
|
+
RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
675
813
|
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)
|
814
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
677
815
|
when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
|
678
|
-
mismatched_foreign_key(message, sql: sql, binds: binds)
|
816
|
+
mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
|
679
817
|
when ER_CANNOT_CREATE_TABLE
|
680
818
|
if message.include?("errno: 150")
|
681
|
-
mismatched_foreign_key(message, sql: sql, binds: binds)
|
819
|
+
mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
|
682
820
|
else
|
683
821
|
super
|
684
822
|
end
|
685
823
|
when ER_DATA_TOO_LONG
|
686
|
-
ValueTooLong.new(message, sql: sql, binds: binds)
|
824
|
+
ValueTooLong.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
687
825
|
when ER_OUT_OF_RANGE
|
688
|
-
RangeError.new(message, sql: sql, binds: binds)
|
826
|
+
RangeError.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
689
827
|
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
690
|
-
NotNullViolation.new(message, sql: sql, binds: binds)
|
828
|
+
NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
691
829
|
when ER_LOCK_DEADLOCK
|
692
|
-
Deadlocked.new(message, sql: sql, binds: binds)
|
830
|
+
Deadlocked.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
693
831
|
when ER_LOCK_WAIT_TIMEOUT
|
694
|
-
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
832
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
695
833
|
when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
|
696
|
-
StatementTimeout.new(message, sql: sql, binds: binds)
|
834
|
+
StatementTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
697
835
|
when ER_QUERY_INTERRUPTED
|
698
|
-
QueryCanceled.new(message, sql: sql, binds: binds)
|
836
|
+
QueryCanceled.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
699
837
|
else
|
700
838
|
super
|
701
839
|
end
|
702
840
|
end
|
703
841
|
|
704
842
|
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))
|
843
|
+
cd = build_change_column_definition(table_name, column_name, type, **options)
|
844
|
+
schema_creation.accept(cd)
|
731
845
|
end
|
732
846
|
|
733
847
|
def rename_column_for_alter(table_name, column_name, new_column_name)
|
@@ -741,7 +855,7 @@ module ActiveRecord
|
|
741
855
|
comment: column.comment
|
742
856
|
}
|
743
857
|
|
744
|
-
current_type =
|
858
|
+
current_type = internal_exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
|
745
859
|
td = create_table_definition(table_name)
|
746
860
|
cd = td.new_column_definition(new_column_name, current_type, **options)
|
747
861
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
@@ -759,6 +873,10 @@ module ActiveRecord
|
|
759
873
|
"DROP INDEX #{quote_column_name(index_name)}"
|
760
874
|
end
|
761
875
|
|
876
|
+
def supports_insert_raw_alias_syntax?
|
877
|
+
!mariadb? && database_version >= "8.0.19"
|
878
|
+
end
|
879
|
+
|
762
880
|
def supports_rename_index?
|
763
881
|
if mariadb?
|
764
882
|
database_version >= "10.5.2"
|
@@ -778,9 +896,6 @@ module ActiveRecord
|
|
778
896
|
def configure_connection
|
779
897
|
variables = @config.fetch(:variables, {}).stringify_keys
|
780
898
|
|
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
899
|
# Increase timeout so the server doesn't disconnect us.
|
785
900
|
wait_timeout = self.class.type_cast_config_to_integer(@config[:wait_timeout])
|
786
901
|
wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
|
@@ -824,7 +939,7 @@ module ActiveRecord
|
|
824
939
|
end.join(", ")
|
825
940
|
|
826
941
|
# ...and send them all in one query
|
827
|
-
|
942
|
+
internal_execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}")
|
828
943
|
end
|
829
944
|
|
830
945
|
def column_definitions(table_name) # :nodoc:
|
@@ -834,7 +949,7 @@ module ActiveRecord
|
|
834
949
|
end
|
835
950
|
|
836
951
|
def create_table_info(table_name) # :nodoc:
|
837
|
-
|
952
|
+
internal_exec_query("SHOW CREATE TABLE #{quote_table_name(table_name)}", "SCHEMA").first["Create Table"]
|
838
953
|
end
|
839
954
|
|
840
955
|
def arel_visitor
|
@@ -845,18 +960,17 @@ module ActiveRecord
|
|
845
960
|
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
846
961
|
end
|
847
962
|
|
848
|
-
def
|
963
|
+
def mismatched_foreign_key_details(message:, sql:)
|
964
|
+
foreign_key_pat =
|
965
|
+
/Referencing column '(\w+)' and referenced/i =~ message ? $1 : '\w+'
|
966
|
+
|
849
967
|
match = %r/
|
850
968
|
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
851
|
-
FOREIGN\s+KEY\s*\(`?(?<foreign_key
|
969
|
+
FOREIGN\s+KEY\s*\(`?(?<foreign_key>#{foreign_key_pat})`?\)\s*
|
852
970
|
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
853
971
|
/xmi.match(sql)
|
854
972
|
|
855
|
-
options = {
|
856
|
-
message: message,
|
857
|
-
sql: sql,
|
858
|
-
binds: binds,
|
859
|
-
}
|
973
|
+
options = {}
|
860
974
|
|
861
975
|
if match
|
862
976
|
options[:table] = match[:table]
|
@@ -866,20 +980,29 @@ module ActiveRecord
|
|
866
980
|
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
867
981
|
end
|
868
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
|
+
|
869
1000
|
MismatchedForeignKey.new(**options)
|
870
1001
|
end
|
871
1002
|
|
872
1003
|
def version_string(full_version_string)
|
873
1004
|
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
874
1005
|
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
1006
|
end
|
884
1007
|
end
|
885
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 &&
|