activerecord 7.0.8.7 → 7.2.3
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 +781 -1777
- data/MIT-LICENSE +1 -1
- data/README.rdoc +30 -30
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +35 -12
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +40 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +22 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +35 -21
- data/lib/active_record/associations/collection_proxy.rb +29 -11
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +21 -14
- data/lib/active_record/associations/has_many_through_association.rb +17 -7
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +4 -3
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +33 -8
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +354 -485
- data/lib/active_record/attribute_assignment.rb +0 -4
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +45 -25
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +8 -7
- data/lib/active_record/attribute_methods/serialization.rb +131 -32
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +153 -33
- data/lib/active_record/attributes.rb +96 -71
- data/lib/active_record/autosave_association.rb +81 -39
- data/lib/active_record/base.rb +11 -7
- data/lib/active_record/callbacks.rb +11 -25
- 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 +123 -131
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +343 -91
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +229 -64
- data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
- 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 +142 -12
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +310 -129
- data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +539 -111
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +289 -128
- 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 +26 -139
- data/lib/active_record/connection_adapters/mysql/quoting.rb +60 -55
- 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 +25 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +108 -68
- data/lib/active_record/connection_adapters/pool_config.rb +20 -10
- 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 +100 -43
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- 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/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
- 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 +153 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +371 -64
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +374 -203
- data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -45
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +51 -8
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +298 -113
- 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 +229 -0
- data/lib/active_record/connection_adapters.rb +124 -1
- data/lib/active_record/connection_handling.rb +101 -105
- data/lib/active_record/core.rb +273 -178
- data/lib/active_record/counter_cache.rb +69 -35
- data/lib/active_record/database_configurations/connection_url_resolver.rb +10 -3
- data/lib/active_record/database_configurations/database_config.rb +26 -5
- data/lib/active_record/database_configurations/hash_config.rb +52 -34
- data/lib/active_record/database_configurations/url_config.rb +37 -12
- data/lib/active_record/database_configurations.rb +87 -34
- data/lib/active_record/delegated_type.rb +56 -27
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- 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 +46 -22
- data/lib/active_record/encryption/encrypted_attribute_type.rb +48 -13
- data/lib/active_record/encryption/encryptor.rb +35 -19
- 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/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +6 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +130 -28
- data/lib/active_record/errors.rb +154 -34
- data/lib/active_record/explain.rb +21 -12
- 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 +48 -10
- data/lib/active_record/fixtures.rb +167 -97
- data/lib/active_record/future_result.rb +47 -8
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +34 -18
- data/lib/active_record/insert_all.rb +72 -22
- data/lib/active_record/integration.rb +11 -8
- data/lib/active_record/internal_metadata.rb +124 -20
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +18 -22
- 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 +106 -8
- data/lib/active_record/migration/compatibility.rb +147 -5
- data/lib/active_record/migration/default_strategy.rb +22 -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 +236 -118
- data/lib/active_record/model_schema.rb +90 -102
- data/lib/active_record/nested_attributes.rb +48 -11
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +168 -339
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +96 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +35 -10
- data/lib/active_record/railtie.rb +131 -87
- data/lib/active_record/railties/controller_runtime.rb +22 -7
- data/lib/active_record/railties/databases.rake +147 -155
- 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 +267 -69
- data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +270 -108
- data/lib/active_record/relation/delegation.rb +30 -19
- data/lib/active_record/relation/finder_methods.rb +97 -21
- data/lib/active_record/relation/merger.rb +6 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -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 +28 -16
- data/lib/active_record/relation/query_attribute.rb +3 -2
- data/lib/active_record/relation/query_methods.rb +585 -109
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +5 -4
- data/lib/active_record/relation/where_clause.rb +15 -21
- data/lib/active_record/relation.rb +592 -92
- data/lib/active_record/result.rb +49 -48
- data/lib/active_record/runtime_registry.rb +63 -1
- data/lib/active_record/sanitization.rb +70 -25
- data/lib/active_record/schema.rb +8 -7
- data/lib/active_record/schema_dumper.rb +90 -23
- data/lib/active_record/schema_migration.rb +75 -24
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +3 -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 +33 -11
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +1 -1
- data/lib/active_record/tasks/database_tasks.rb +190 -118
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +23 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_fixtures.rb +170 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +31 -17
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +108 -24
- data/lib/active_record/translation.rb +0 -2
- 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 +1 -3
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +9 -3
- 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 +61 -11
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +247 -33
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +3 -1
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +2 -0
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +4 -2
- 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/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +6 -2
- data/lib/arel/predications.rb +3 -1
- data/lib/arel/select_manager.rb +7 -3
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -0
- data/lib/arel/visitors/mysql.rb +17 -5
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +114 -34
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +21 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- 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 +56 -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
|
|
@@ -138,6 +170,14 @@ module ActiveRecord
|
|
|
138
170
|
true
|
|
139
171
|
end
|
|
140
172
|
|
|
173
|
+
def supports_insert_returning?
|
|
174
|
+
mariadb? && database_version >= "10.5.0"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def return_value_after_insert?(column) # :nodoc:
|
|
178
|
+
supports_insert_returning? ? column.auto_populated? : column.auto_increment?
|
|
179
|
+
end
|
|
180
|
+
|
|
141
181
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
|
142
182
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
|
143
183
|
end
|
|
@@ -182,7 +222,7 @@ module ActiveRecord
|
|
|
182
222
|
update("SET FOREIGN_KEY_CHECKS = 0")
|
|
183
223
|
yield
|
|
184
224
|
ensure
|
|
185
|
-
update("SET FOREIGN_KEY_CHECKS = #{old}")
|
|
225
|
+
update("SET FOREIGN_KEY_CHECKS = #{old}") if active?
|
|
186
226
|
end
|
|
187
227
|
end
|
|
188
228
|
|
|
@@ -190,33 +230,36 @@ module ActiveRecord
|
|
|
190
230
|
# DATABASE STATEMENTS ======================================
|
|
191
231
|
#++
|
|
192
232
|
|
|
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
233
|
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
|
199
234
|
# to write stuff in an abstract way without concerning ourselves about whether it
|
|
200
235
|
# needs to be explicitly freed or not.
|
|
201
|
-
def execute_and_free(sql, name = nil, async: false) # :nodoc:
|
|
202
|
-
|
|
236
|
+
def execute_and_free(sql, name = nil, async: false, allow_retry: false) # :nodoc:
|
|
237
|
+
sql = transform_query(sql)
|
|
238
|
+
check_if_write_query(sql)
|
|
239
|
+
|
|
240
|
+
mark_transaction_written_if_write(sql)
|
|
241
|
+
yield raw_execute(sql, name, async: async, allow_retry: allow_retry)
|
|
203
242
|
end
|
|
204
243
|
|
|
205
244
|
def begin_db_transaction # :nodoc:
|
|
206
|
-
|
|
245
|
+
internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
207
246
|
end
|
|
208
247
|
|
|
209
248
|
def begin_isolated_db_transaction(isolation) # :nodoc:
|
|
210
|
-
|
|
249
|
+
internal_execute("SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
211
250
|
begin_db_transaction
|
|
212
251
|
end
|
|
213
252
|
|
|
214
253
|
def commit_db_transaction # :nodoc:
|
|
215
|
-
|
|
254
|
+
internal_execute("COMMIT", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
|
216
255
|
end
|
|
217
256
|
|
|
218
257
|
def exec_rollback_db_transaction # :nodoc:
|
|
219
|
-
|
|
258
|
+
internal_execute("ROLLBACK", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def exec_restart_db_transaction # :nodoc:
|
|
262
|
+
internal_execute("ROLLBACK AND CHAIN", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
|
220
263
|
end
|
|
221
264
|
|
|
222
265
|
def empty_insert_statement_value(primary_key = nil) # :nodoc:
|
|
@@ -296,11 +339,12 @@ module ActiveRecord
|
|
|
296
339
|
#
|
|
297
340
|
# Example:
|
|
298
341
|
# rename_table('octopuses', 'octopi')
|
|
299
|
-
def rename_table(table_name, new_name)
|
|
342
|
+
def rename_table(table_name, new_name, **options)
|
|
343
|
+
validate_table_length!(new_name) unless options[:_uses_legacy_table_name]
|
|
300
344
|
schema_cache.clear_data_source_cache!(table_name.to_s)
|
|
301
345
|
schema_cache.clear_data_source_cache!(new_name.to_s)
|
|
302
346
|
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
|
303
|
-
rename_table_indexes(table_name, new_name)
|
|
347
|
+
rename_table_indexes(table_name, new_name, **options)
|
|
304
348
|
end
|
|
305
349
|
|
|
306
350
|
# Drops a table from the database.
|
|
@@ -334,11 +378,20 @@ module ActiveRecord
|
|
|
334
378
|
end
|
|
335
379
|
|
|
336
380
|
def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
|
|
381
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{change_column_default_for_alter(table_name, column_name, default_or_changes)}"
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def build_change_column_default_definition(table_name, column_name, default_or_changes) # :nodoc:
|
|
385
|
+
column = column_for(table_name, column_name)
|
|
386
|
+
return unless column
|
|
387
|
+
|
|
337
388
|
default = extract_new_default_value(default_or_changes)
|
|
338
|
-
|
|
389
|
+
ChangeColumnDefaultDefinition.new(column, default)
|
|
339
390
|
end
|
|
340
391
|
|
|
341
392
|
def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
|
|
393
|
+
validate_change_column_null_argument!(null)
|
|
394
|
+
|
|
342
395
|
unless null || default.nil?
|
|
343
396
|
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
|
344
397
|
end
|
|
@@ -355,18 +408,64 @@ module ActiveRecord
|
|
|
355
408
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
|
|
356
409
|
end
|
|
357
410
|
|
|
411
|
+
# Builds a ChangeColumnDefinition object.
|
|
412
|
+
#
|
|
413
|
+
# This definition object contains information about the column change that would occur
|
|
414
|
+
# if the same arguments were passed to #change_column. See #change_column for information about
|
|
415
|
+
# passing a +table_name+, +column_name+, +type+ and other options that can be passed.
|
|
416
|
+
def build_change_column_definition(table_name, column_name, type, **options) # :nodoc:
|
|
417
|
+
column = column_for(table_name, column_name)
|
|
418
|
+
type ||= column.sql_type
|
|
419
|
+
|
|
420
|
+
unless options.key?(:default)
|
|
421
|
+
options[:default] = if column.default_function
|
|
422
|
+
-> { column.default_function }
|
|
423
|
+
else
|
|
424
|
+
column.default
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
unless options.key?(:null)
|
|
429
|
+
options[:null] = column.null
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
unless options.key?(:comment)
|
|
433
|
+
options[:comment] = column.comment
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
if options[:collation] == :no_collation
|
|
437
|
+
options.delete(:collation)
|
|
438
|
+
else
|
|
439
|
+
options[:collation] ||= column.collation if text_type?(type)
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
unless options.key?(:auto_increment)
|
|
443
|
+
options[:auto_increment] = column.auto_increment?
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
td = create_table_definition(table_name)
|
|
447
|
+
cd = td.new_column_definition(column.name, type, **options)
|
|
448
|
+
ChangeColumnDefinition.new(cd, column.name)
|
|
449
|
+
end
|
|
450
|
+
|
|
358
451
|
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
|
359
452
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
|
|
360
453
|
rename_column_indexes(table_name, column_name, new_column_name)
|
|
361
454
|
end
|
|
362
455
|
|
|
363
456
|
def add_index(table_name, column_name, **options) # :nodoc:
|
|
457
|
+
create_index = build_create_index_definition(table_name, column_name, **options)
|
|
458
|
+
return unless create_index
|
|
459
|
+
|
|
460
|
+
execute schema_creation.accept(create_index)
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
def build_create_index_definition(table_name, column_name, **options) # :nodoc:
|
|
364
464
|
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
|
365
465
|
|
|
366
466
|
return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
|
|
367
467
|
|
|
368
|
-
|
|
369
|
-
execute schema_creation.accept(create_index)
|
|
468
|
+
CreateIndexDefinition.new(index, algorithm)
|
|
370
469
|
end
|
|
371
470
|
|
|
372
471
|
def add_sql_comment!(sql, comment) # :nodoc:
|
|
@@ -379,11 +478,13 @@ module ActiveRecord
|
|
|
379
478
|
|
|
380
479
|
scope = quoted_scope(table_name)
|
|
381
480
|
|
|
382
|
-
|
|
481
|
+
# MySQL returns 1 row for each column of composite foreign keys.
|
|
482
|
+
fk_info = internal_exec_query(<<~SQL, "SCHEMA")
|
|
383
483
|
SELECT fk.referenced_table_name AS 'to_table',
|
|
384
484
|
fk.referenced_column_name AS 'primary_key',
|
|
385
485
|
fk.column_name AS 'column',
|
|
386
486
|
fk.constraint_name AS 'name',
|
|
487
|
+
fk.ordinal_position AS 'position',
|
|
387
488
|
rc.update_rule AS 'on_update',
|
|
388
489
|
rc.delete_rule AS 'on_delete'
|
|
389
490
|
FROM information_schema.referential_constraints rc
|
|
@@ -396,15 +497,22 @@ module ActiveRecord
|
|
|
396
497
|
AND rc.table_name = #{scope[:name]}
|
|
397
498
|
SQL
|
|
398
499
|
|
|
399
|
-
fk_info.
|
|
500
|
+
grouped_fk = fk_info.group_by { |row| row["name"] }.values.each { |group| group.sort_by! { |row| row["position"] } }
|
|
501
|
+
grouped_fk.map do |group|
|
|
502
|
+
row = group.first
|
|
400
503
|
options = {
|
|
401
|
-
column: unquote_identifier(row["column"]),
|
|
402
504
|
name: row["name"],
|
|
403
|
-
|
|
505
|
+
on_update: extract_foreign_key_action(row["on_update"]),
|
|
506
|
+
on_delete: extract_foreign_key_action(row["on_delete"])
|
|
404
507
|
}
|
|
405
508
|
|
|
406
|
-
|
|
407
|
-
|
|
509
|
+
if group.one?
|
|
510
|
+
options[:column] = unquote_identifier(row["column"])
|
|
511
|
+
options[:primary_key] = row["primary_key"]
|
|
512
|
+
else
|
|
513
|
+
options[:column] = group.map { |row| unquote_identifier(row["column"]) }
|
|
514
|
+
options[:primary_key] = group.map { |row| row["primary_key"] }
|
|
515
|
+
end
|
|
408
516
|
|
|
409
517
|
ForeignKeyDefinition.new(table_name, unquote_identifier(row["to_table"]), options)
|
|
410
518
|
end
|
|
@@ -426,7 +534,7 @@ module ActiveRecord
|
|
|
426
534
|
SQL
|
|
427
535
|
sql += " AND cc.table_name = #{scope[:name]}" if mariadb?
|
|
428
536
|
|
|
429
|
-
chk_info =
|
|
537
|
+
chk_info = internal_exec_query(sql, "SCHEMA")
|
|
430
538
|
|
|
431
539
|
chk_info.map do |row|
|
|
432
540
|
options = {
|
|
@@ -435,6 +543,13 @@ module ActiveRecord
|
|
|
435
543
|
expression = row["expression"]
|
|
436
544
|
expression = expression[1..-2] if expression.start_with?("(") && expression.end_with?(")")
|
|
437
545
|
expression = strip_whitespace_characters(expression)
|
|
546
|
+
|
|
547
|
+
unless mariadb?
|
|
548
|
+
# MySQL returns check constraints expression in an already escaped form.
|
|
549
|
+
# This leads to duplicate escaping later (e.g. when the expression is used in the SchemaDumper).
|
|
550
|
+
expression = expression.gsub("\\'", "'")
|
|
551
|
+
end
|
|
552
|
+
|
|
438
553
|
CheckConstraintDefinition.new(table_name, expression, options)
|
|
439
554
|
end
|
|
440
555
|
else
|
|
@@ -532,40 +647,81 @@ module ActiveRecord
|
|
|
532
647
|
end
|
|
533
648
|
|
|
534
649
|
def build_insert_sql(insert) # :nodoc:
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
650
|
+
# Can use any column as it will be assigned to itself.
|
|
651
|
+
no_op_column = quote_column_name(insert.keys.first) if insert.keys.first
|
|
652
|
+
|
|
653
|
+
# MySQL 8.0.19 replaces `VALUES(<expression>)` clauses with row and column alias names, see https://dev.mysql.com/worklog/task/?id=6312 .
|
|
654
|
+
# then MySQL 8.0.20 deprecates the `VALUES(<expression>)` see https://dev.mysql.com/worklog/task/?id=13325 .
|
|
655
|
+
if supports_insert_raw_alias_syntax?
|
|
656
|
+
quoted_table_name = insert.model.quoted_table_name
|
|
657
|
+
values_alias = quote_table_name("#{insert.model.table_name.parameterize}_values")
|
|
658
|
+
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"
|
|
659
|
+
|
|
660
|
+
if insert.skip_duplicates?
|
|
661
|
+
if no_op_column
|
|
662
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{quoted_table_name}.#{no_op_column}"
|
|
663
|
+
end
|
|
664
|
+
elsif insert.update_duplicates?
|
|
665
|
+
if insert.raw_update_sql?
|
|
666
|
+
sql = +"INSERT #{insert.into} #{insert.values_list} ON DUPLICATE KEY UPDATE #{insert.raw_update_sql}"
|
|
667
|
+
else
|
|
668
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
|
669
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{quoted_table_name}.#{column}<=>#{values_alias}.#{column}" }
|
|
670
|
+
sql << insert.updatable_columns.map { |column| "#{column}=#{values_alias}.#{column}" }.join(",")
|
|
671
|
+
end
|
|
672
|
+
end
|
|
673
|
+
else
|
|
674
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
|
675
|
+
|
|
676
|
+
if insert.skip_duplicates?
|
|
677
|
+
if no_op_column
|
|
678
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
|
679
|
+
end
|
|
680
|
+
elsif insert.update_duplicates?
|
|
681
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
|
682
|
+
if insert.raw_update_sql?
|
|
683
|
+
sql << insert.raw_update_sql
|
|
684
|
+
else
|
|
685
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
|
|
686
|
+
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
|
687
|
+
end
|
|
547
688
|
end
|
|
548
689
|
end
|
|
549
690
|
|
|
691
|
+
sql << " RETURNING #{insert.returning}" if insert.returning
|
|
550
692
|
sql
|
|
551
693
|
end
|
|
552
694
|
|
|
553
695
|
def check_version # :nodoc:
|
|
554
696
|
if database_version < "5.5.8"
|
|
555
|
-
raise "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
|
|
697
|
+
raise DatabaseVersionError, "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
|
|
698
|
+
end
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
#--
|
|
702
|
+
# QUOTING ==================================================
|
|
703
|
+
#++
|
|
704
|
+
|
|
705
|
+
# Quotes strings for use in SQL input.
|
|
706
|
+
def quote_string(string)
|
|
707
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |connection|
|
|
708
|
+
connection.escape(string)
|
|
556
709
|
end
|
|
557
710
|
end
|
|
558
711
|
|
|
559
712
|
class << self
|
|
713
|
+
def extended_type_map(default_timezone: nil, emulate_booleans:) # :nodoc:
|
|
714
|
+
super(default_timezone: default_timezone).tap do |m|
|
|
715
|
+
if emulate_booleans
|
|
716
|
+
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
|
|
717
|
+
end
|
|
718
|
+
end
|
|
719
|
+
end
|
|
720
|
+
|
|
560
721
|
private
|
|
561
722
|
def initialize_type_map(m)
|
|
562
723
|
super
|
|
563
724
|
|
|
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
725
|
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
|
570
726
|
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
|
571
727
|
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
|
|
@@ -585,9 +741,6 @@ module ActiveRecord
|
|
|
585
741
|
|
|
586
742
|
m.alias_type %r(year)i, "integer"
|
|
587
743
|
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
744
|
end
|
|
592
745
|
|
|
593
746
|
def register_integer_type(mapping, key, **options)
|
|
@@ -609,41 +762,53 @@ module ActiveRecord
|
|
|
609
762
|
end
|
|
610
763
|
end
|
|
611
764
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
|
|
615
|
-
end
|
|
765
|
+
EXTENDED_TYPE_MAPS = Concurrent::Map.new
|
|
766
|
+
EMULATE_BOOLEANS_TRUE = { emulate_booleans: true }.freeze
|
|
616
767
|
|
|
617
768
|
private
|
|
618
769
|
def strip_whitespace_characters(expression)
|
|
619
|
-
expression
|
|
620
|
-
expression = expression.gsub(/\s{2,}/, " ")
|
|
621
|
-
expression
|
|
770
|
+
expression.gsub('\\\n', "").gsub("x0A", "").squish
|
|
622
771
|
end
|
|
623
772
|
|
|
624
|
-
def
|
|
625
|
-
|
|
773
|
+
def extended_type_map_key
|
|
774
|
+
if @default_timezone
|
|
775
|
+
{ default_timezone: @default_timezone, emulate_booleans: emulate_booleans }
|
|
776
|
+
elsif emulate_booleans
|
|
777
|
+
EMULATE_BOOLEANS_TRUE
|
|
778
|
+
end
|
|
626
779
|
end
|
|
627
780
|
|
|
628
|
-
def
|
|
629
|
-
|
|
630
|
-
end
|
|
781
|
+
def handle_warnings(sql)
|
|
782
|
+
return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
|
|
631
783
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
784
|
+
@affected_rows_before_warnings = @raw_connection.affected_rows
|
|
785
|
+
warning_count = @raw_connection.warning_count
|
|
786
|
+
result = @raw_connection.query("SHOW WARNINGS")
|
|
787
|
+
result = [
|
|
788
|
+
["Warning", nil, "Query had warning_count=#{warning_count} but ‘SHOW WARNINGS’ did not return the warnings. Check MySQL logs or database configuration."],
|
|
789
|
+
] if result.count == 0
|
|
790
|
+
result.each do |level, code, message|
|
|
791
|
+
warning = SQLWarning.new(message, code, level, sql, @pool)
|
|
792
|
+
next if warning_ignored?(warning)
|
|
635
793
|
|
|
636
|
-
|
|
637
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
|
638
|
-
@connection.query(sql)
|
|
639
|
-
end
|
|
794
|
+
ActiveRecord.db_warnings_action.call(warning)
|
|
640
795
|
end
|
|
641
796
|
end
|
|
642
797
|
|
|
798
|
+
def warning_ignored?(warning)
|
|
799
|
+
warning.level == "Note" || super
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
|
803
|
+
# made since we established the connection
|
|
804
|
+
def sync_timezone_changes(raw_connection)
|
|
805
|
+
end
|
|
806
|
+
|
|
643
807
|
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
|
|
644
808
|
ER_DB_CREATE_EXISTS = 1007
|
|
645
809
|
ER_FILSORT_ABORT = 1028
|
|
646
810
|
ER_DUP_ENTRY = 1062
|
|
811
|
+
ER_SERVER_SHUTDOWN = 1053
|
|
647
812
|
ER_NOT_NULL_VIOLATION = 1048
|
|
648
813
|
ER_NO_REFERENCED_ROW = 1216
|
|
649
814
|
ER_ROW_IS_REFERENCED = 1217
|
|
@@ -657,77 +822,59 @@ module ActiveRecord
|
|
|
657
822
|
ER_CANNOT_CREATE_TABLE = 1005
|
|
658
823
|
ER_LOCK_WAIT_TIMEOUT = 1205
|
|
659
824
|
ER_QUERY_INTERRUPTED = 1317
|
|
825
|
+
ER_CONNECTION_KILLED = 1927
|
|
826
|
+
CR_SERVER_GONE_ERROR = 2006
|
|
827
|
+
CR_SERVER_LOST = 2013
|
|
660
828
|
ER_QUERY_TIMEOUT = 3024
|
|
661
829
|
ER_FK_INCOMPATIBLE_COLUMNS = 3780
|
|
830
|
+
ER_CLIENT_INTERACTION_TIMEOUT = 4031
|
|
662
831
|
|
|
663
832
|
def translate_exception(exception, message:, sql:, binds:)
|
|
664
833
|
case error_number(exception)
|
|
665
834
|
when nil
|
|
666
835
|
if exception.message.match?(/MySQL client is not connected/i)
|
|
667
|
-
ConnectionNotEstablished.new(exception)
|
|
836
|
+
ConnectionNotEstablished.new(exception, connection_pool: @pool)
|
|
668
837
|
else
|
|
669
838
|
super
|
|
670
839
|
end
|
|
840
|
+
when ER_CONNECTION_KILLED, ER_SERVER_SHUTDOWN, CR_SERVER_GONE_ERROR, CR_SERVER_LOST, ER_CLIENT_INTERACTION_TIMEOUT
|
|
841
|
+
ConnectionFailed.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
671
842
|
when ER_DB_CREATE_EXISTS
|
|
672
|
-
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
|
|
843
|
+
DatabaseAlreadyExists.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
673
844
|
when ER_DUP_ENTRY
|
|
674
|
-
RecordNotUnique.new(message, sql: sql, binds: binds)
|
|
845
|
+
RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
675
846
|
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)
|
|
847
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
677
848
|
when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
|
|
678
|
-
mismatched_foreign_key(message, sql: sql, binds: binds)
|
|
849
|
+
mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
679
850
|
when ER_CANNOT_CREATE_TABLE
|
|
680
851
|
if message.include?("errno: 150")
|
|
681
|
-
mismatched_foreign_key(message, sql: sql, binds: binds)
|
|
852
|
+
mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
682
853
|
else
|
|
683
854
|
super
|
|
684
855
|
end
|
|
685
856
|
when ER_DATA_TOO_LONG
|
|
686
|
-
ValueTooLong.new(message, sql: sql, binds: binds)
|
|
857
|
+
ValueTooLong.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
687
858
|
when ER_OUT_OF_RANGE
|
|
688
|
-
RangeError.new(message, sql: sql, binds: binds)
|
|
859
|
+
RangeError.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
689
860
|
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
|
690
|
-
NotNullViolation.new(message, sql: sql, binds: binds)
|
|
861
|
+
NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
691
862
|
when ER_LOCK_DEADLOCK
|
|
692
|
-
Deadlocked.new(message, sql: sql, binds: binds)
|
|
863
|
+
Deadlocked.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
693
864
|
when ER_LOCK_WAIT_TIMEOUT
|
|
694
|
-
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
|
865
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
695
866
|
when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
|
|
696
|
-
StatementTimeout.new(message, sql: sql, binds: binds)
|
|
867
|
+
StatementTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
697
868
|
when ER_QUERY_INTERRUPTED
|
|
698
|
-
QueryCanceled.new(message, sql: sql, binds: binds)
|
|
869
|
+
QueryCanceled.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
699
870
|
else
|
|
700
871
|
super
|
|
701
872
|
end
|
|
702
873
|
end
|
|
703
874
|
|
|
704
875
|
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))
|
|
876
|
+
cd = build_change_column_definition(table_name, column_name, type, **options)
|
|
877
|
+
schema_creation.accept(cd)
|
|
731
878
|
end
|
|
732
879
|
|
|
733
880
|
def rename_column_for_alter(table_name, column_name, new_column_name)
|
|
@@ -741,7 +888,7 @@ module ActiveRecord
|
|
|
741
888
|
comment: column.comment
|
|
742
889
|
}
|
|
743
890
|
|
|
744
|
-
current_type =
|
|
891
|
+
current_type = internal_exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
|
|
745
892
|
td = create_table_definition(table_name)
|
|
746
893
|
cd = td.new_column_definition(new_column_name, current_type, **options)
|
|
747
894
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
|
@@ -759,6 +906,10 @@ module ActiveRecord
|
|
|
759
906
|
"DROP INDEX #{quote_column_name(index_name)}"
|
|
760
907
|
end
|
|
761
908
|
|
|
909
|
+
def supports_insert_raw_alias_syntax?
|
|
910
|
+
!mariadb? && database_version >= "8.0.19"
|
|
911
|
+
end
|
|
912
|
+
|
|
762
913
|
def supports_rename_index?
|
|
763
914
|
if mariadb?
|
|
764
915
|
database_version >= "10.5.2"
|
|
@@ -776,11 +927,9 @@ module ActiveRecord
|
|
|
776
927
|
end
|
|
777
928
|
|
|
778
929
|
def configure_connection
|
|
930
|
+
super
|
|
779
931
|
variables = @config.fetch(:variables, {}).stringify_keys
|
|
780
932
|
|
|
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
933
|
# Increase timeout so the server doesn't disconnect us.
|
|
785
934
|
wait_timeout = self.class.type_cast_config_to_integer(@config[:wait_timeout])
|
|
786
935
|
wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
|
|
@@ -824,7 +973,7 @@ module ActiveRecord
|
|
|
824
973
|
end.join(", ")
|
|
825
974
|
|
|
826
975
|
# ...and send them all in one query
|
|
827
|
-
|
|
976
|
+
internal_execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}")
|
|
828
977
|
end
|
|
829
978
|
|
|
830
979
|
def column_definitions(table_name) # :nodoc:
|
|
@@ -834,7 +983,7 @@ module ActiveRecord
|
|
|
834
983
|
end
|
|
835
984
|
|
|
836
985
|
def create_table_info(table_name) # :nodoc:
|
|
837
|
-
|
|
986
|
+
internal_exec_query("SHOW CREATE TABLE #{quote_table_name(table_name)}", "SCHEMA").first["Create Table"]
|
|
838
987
|
end
|
|
839
988
|
|
|
840
989
|
def arel_visitor
|
|
@@ -845,18 +994,17 @@ module ActiveRecord
|
|
|
845
994
|
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
|
846
995
|
end
|
|
847
996
|
|
|
848
|
-
def
|
|
997
|
+
def mismatched_foreign_key_details(message:, sql:)
|
|
998
|
+
foreign_key_pat =
|
|
999
|
+
/Referencing column '(\w+)' and referenced/i =~ message ? $1 : '\w+'
|
|
1000
|
+
|
|
849
1001
|
match = %r/
|
|
850
1002
|
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
|
851
|
-
FOREIGN\s+KEY\s*\(`?(?<foreign_key
|
|
1003
|
+
FOREIGN\s+KEY\s*\(`?(?<foreign_key>#{foreign_key_pat})`?\)\s*
|
|
852
1004
|
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
|
853
1005
|
/xmi.match(sql)
|
|
854
1006
|
|
|
855
|
-
options = {
|
|
856
|
-
message: message,
|
|
857
|
-
sql: sql,
|
|
858
|
-
binds: binds,
|
|
859
|
-
}
|
|
1007
|
+
options = {}
|
|
860
1008
|
|
|
861
1009
|
if match
|
|
862
1010
|
options[:table] = match[:table]
|
|
@@ -866,20 +1014,33 @@ module ActiveRecord
|
|
|
866
1014
|
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
|
867
1015
|
end
|
|
868
1016
|
|
|
869
|
-
|
|
1017
|
+
options
|
|
870
1018
|
end
|
|
871
1019
|
|
|
872
|
-
def
|
|
873
|
-
|
|
874
|
-
|
|
1020
|
+
def mismatched_foreign_key(message, sql:, binds:, connection_pool:)
|
|
1021
|
+
options = {
|
|
1022
|
+
message: message,
|
|
1023
|
+
sql: sql,
|
|
1024
|
+
binds: binds,
|
|
1025
|
+
connection_pool: connection_pool
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
if sql
|
|
1029
|
+
options.update mismatched_foreign_key_details(message: message, sql: sql)
|
|
1030
|
+
else
|
|
1031
|
+
options[:query_parser] = ->(sql) { mismatched_foreign_key_details(message: message, sql: sql) }
|
|
1032
|
+
end
|
|
875
1033
|
|
|
876
|
-
|
|
877
|
-
Type::ImmutableString.new(true: "1", false: "0", **args)
|
|
1034
|
+
MismatchedForeignKey.new(**options)
|
|
878
1035
|
end
|
|
879
|
-
|
|
880
|
-
|
|
1036
|
+
|
|
1037
|
+
def version_string(full_version_string)
|
|
1038
|
+
if full_version_string && matches = full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)
|
|
1039
|
+
matches[1]
|
|
1040
|
+
else
|
|
1041
|
+
raise DatabaseVersionError, "Unable to parse MySQL version from #{full_version_string.inspect}"
|
|
1042
|
+
end
|
|
881
1043
|
end
|
|
882
|
-
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
|
|
883
1044
|
end
|
|
884
1045
|
end
|
|
885
1046
|
end
|