activerecord 7.0.0 → 7.2.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 +515 -1268
- data/MIT-LICENSE +1 -1
- data/README.rdoc +31 -31
- 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 +25 -19
- 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 +23 -8
- 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 +28 -17
- data/lib/active_record/associations/collection_proxy.rb +36 -13
- 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 +28 -18
- 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 +27 -25
- data/lib/active_record/associations/join_dependency.rb +18 -14
- 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 +2 -4
- 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 +378 -491
- data/lib/active_record/attribute_assignment.rb +1 -13
- 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 +153 -70
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -6
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +153 -40
- data/lib/active_record/attributes.rb +63 -48
- data/lib/active_record/autosave_association.rb +70 -38
- data/lib/active_record/base.rb +12 -8
- 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 -34
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +124 -132
- 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 +297 -88
- 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 +215 -63
- data/lib/active_record/connection_adapters/abstract/quoting.rb +83 -65
- 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 +163 -29
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +319 -135
- data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +512 -126
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +282 -119
- 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 +27 -140
- data/lib/active_record/connection_adapters/mysql/quoting.rb +64 -52
- 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 +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +101 -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 +16 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +101 -48
- 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/hstore.rb +2 -2
- 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 +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +94 -61
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +6 -10
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +151 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +379 -66
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +370 -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 +61 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +64 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +321 -110
- 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 +98 -106
- data/lib/active_record/core.rb +220 -177
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -2
- 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 +88 -35
- data/lib/active_record/delegated_type.rb +40 -11
- 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/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 +13 -14
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +8 -4
- data/lib/active_record/encryption/derived_secret_key_provider.rb +9 -3
- data/lib/active_record/encryption/deterministic_key_provider.rb +1 -1
- data/lib/active_record/encryption/encryptable_record.rb +47 -25
- data/lib/active_record/encryption/encrypted_attribute_type.rb +49 -14
- data/lib/active_record/encryption/encryptor.rb +25 -10
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +3 -3
- data/lib/active_record/encryption/extended_deterministic_queries.rb +83 -86
- 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.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 +4 -4
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +23 -22
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +131 -27
- data/lib/active_record/errors.rb +151 -31
- data/lib/active_record/explain.rb +21 -12
- 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 +169 -99
- data/lib/active_record/future_result.rb +47 -8
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +34 -18
- data/lib/active_record/insert_all.rb +72 -22
- data/lib/active_record/integration.rb +13 -10
- data/lib/active_record/internal_metadata.rb +124 -20
- data/lib/active_record/locking/optimistic.rb +39 -24
- data/lib/active_record/locking/pessimistic.rb +8 -5
- data/lib/active_record/log_subscriber.rb +28 -27
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +18 -13
- data/lib/active_record/middleware/shard_selector.rb +7 -5
- data/lib/active_record/migration/command_recorder.rb +110 -13
- data/lib/active_record/migration/compatibility.rb +174 -64
- 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 +292 -125
- data/lib/active_record/model_schema.rb +113 -112
- data/lib/active_record/nested_attributes.rb +35 -9
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +177 -345
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +19 -25
- data/lib/active_record/query_logs.rb +102 -51
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +34 -9
- data/lib/active_record/railtie.rb +153 -100
- data/lib/active_record/railties/controller_runtime.rb +24 -10
- data/lib/active_record/railties/databases.rake +148 -152
- 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 +278 -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 +293 -108
- data/lib/active_record/relation/delegation.rb +31 -20
- data/lib/active_record/relation/finder_methods.rb +93 -18
- 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 +38 -4
- 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 +25 -1
- data/lib/active_record/relation/query_methods.rb +625 -107
- 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 +7 -19
- data/lib/active_record/relation.rb +602 -96
- data/lib/active_record/result.rb +55 -52
- data/lib/active_record/runtime_registry.rb +63 -1
- data/lib/active_record/sanitization.rb +76 -30
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +82 -30
- data/lib/active_record/schema_migration.rb +75 -24
- data/lib/active_record/scoping/default.rb +20 -12
- 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/serialization.rb +5 -0
- data/lib/active_record/signed_id.rb +29 -8
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +16 -11
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +191 -121
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +17 -15
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_fixtures.rb +174 -152
- 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 +109 -27
- data/lib/active_record/translation.rb +1 -3
- 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 +9 -7
- 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 +12 -6
- 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 +63 -14
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +266 -30
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +2 -0
- 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/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +1 -1
- 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/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/{and.rb → nary.rb} +9 -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.rb +6 -2
- data/lib/arel/predications.rb +3 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +17 -5
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/to_sql.rb +112 -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 +59 -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,9 +170,8 @@ module ActiveRecord
|
|
|
138
170
|
true
|
|
139
171
|
end
|
|
140
172
|
|
|
141
|
-
def
|
|
142
|
-
|
|
143
|
-
Arel::Nodes::Descending.new(field)
|
|
173
|
+
def supports_insert_returning?
|
|
174
|
+
mariadb? && database_version >= "10.5.0"
|
|
144
175
|
end
|
|
145
176
|
|
|
146
177
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
|
@@ -187,7 +218,7 @@ module ActiveRecord
|
|
|
187
218
|
update("SET FOREIGN_KEY_CHECKS = 0")
|
|
188
219
|
yield
|
|
189
220
|
ensure
|
|
190
|
-
update("SET FOREIGN_KEY_CHECKS = #{old}")
|
|
221
|
+
update("SET FOREIGN_KEY_CHECKS = #{old}") if active?
|
|
191
222
|
end
|
|
192
223
|
end
|
|
193
224
|
|
|
@@ -195,33 +226,36 @@ module ActiveRecord
|
|
|
195
226
|
# DATABASE STATEMENTS ======================================
|
|
196
227
|
#++
|
|
197
228
|
|
|
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)
|
|
201
|
-
end
|
|
202
|
-
|
|
203
229
|
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
|
204
230
|
# to write stuff in an abstract way without concerning ourselves about whether it
|
|
205
231
|
# needs to be explicitly freed or not.
|
|
206
|
-
def execute_and_free(sql, name = nil, async: false) # :nodoc:
|
|
207
|
-
|
|
232
|
+
def execute_and_free(sql, name = nil, async: false, allow_retry: false) # :nodoc:
|
|
233
|
+
sql = transform_query(sql)
|
|
234
|
+
check_if_write_query(sql)
|
|
235
|
+
|
|
236
|
+
mark_transaction_written_if_write(sql)
|
|
237
|
+
yield raw_execute(sql, name, async: async, allow_retry: allow_retry)
|
|
208
238
|
end
|
|
209
239
|
|
|
210
240
|
def begin_db_transaction # :nodoc:
|
|
211
|
-
|
|
241
|
+
internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
212
242
|
end
|
|
213
243
|
|
|
214
244
|
def begin_isolated_db_transaction(isolation) # :nodoc:
|
|
215
|
-
|
|
245
|
+
internal_execute("SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
216
246
|
begin_db_transaction
|
|
217
247
|
end
|
|
218
248
|
|
|
219
249
|
def commit_db_transaction # :nodoc:
|
|
220
|
-
|
|
250
|
+
internal_execute("COMMIT", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
|
221
251
|
end
|
|
222
252
|
|
|
223
253
|
def exec_rollback_db_transaction # :nodoc:
|
|
224
|
-
|
|
254
|
+
internal_execute("ROLLBACK", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def exec_restart_db_transaction # :nodoc:
|
|
258
|
+
internal_execute("ROLLBACK AND CHAIN", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
|
225
259
|
end
|
|
226
260
|
|
|
227
261
|
def empty_insert_statement_value(primary_key = nil) # :nodoc:
|
|
@@ -301,11 +335,12 @@ module ActiveRecord
|
|
|
301
335
|
#
|
|
302
336
|
# Example:
|
|
303
337
|
# rename_table('octopuses', 'octopi')
|
|
304
|
-
def rename_table(table_name, new_name)
|
|
338
|
+
def rename_table(table_name, new_name, **options)
|
|
339
|
+
validate_table_length!(new_name) unless options[:_uses_legacy_table_name]
|
|
305
340
|
schema_cache.clear_data_source_cache!(table_name.to_s)
|
|
306
341
|
schema_cache.clear_data_source_cache!(new_name.to_s)
|
|
307
342
|
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
|
308
|
-
rename_table_indexes(table_name, new_name)
|
|
343
|
+
rename_table_indexes(table_name, new_name, **options)
|
|
309
344
|
end
|
|
310
345
|
|
|
311
346
|
# Drops a table from the database.
|
|
@@ -339,11 +374,20 @@ module ActiveRecord
|
|
|
339
374
|
end
|
|
340
375
|
|
|
341
376
|
def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
|
|
377
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{change_column_default_for_alter(table_name, column_name, default_or_changes)}"
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
def build_change_column_default_definition(table_name, column_name, default_or_changes) # :nodoc:
|
|
381
|
+
column = column_for(table_name, column_name)
|
|
382
|
+
return unless column
|
|
383
|
+
|
|
342
384
|
default = extract_new_default_value(default_or_changes)
|
|
343
|
-
|
|
385
|
+
ChangeColumnDefaultDefinition.new(column, default)
|
|
344
386
|
end
|
|
345
387
|
|
|
346
388
|
def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
|
|
389
|
+
validate_change_column_null_argument!(null)
|
|
390
|
+
|
|
347
391
|
unless null || default.nil?
|
|
348
392
|
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
|
349
393
|
end
|
|
@@ -360,18 +404,60 @@ module ActiveRecord
|
|
|
360
404
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
|
|
361
405
|
end
|
|
362
406
|
|
|
407
|
+
# Builds a ChangeColumnDefinition object.
|
|
408
|
+
#
|
|
409
|
+
# This definition object contains information about the column change that would occur
|
|
410
|
+
# if the same arguments were passed to #change_column. See #change_column for information about
|
|
411
|
+
# passing a +table_name+, +column_name+, +type+ and other options that can be passed.
|
|
412
|
+
def build_change_column_definition(table_name, column_name, type, **options) # :nodoc:
|
|
413
|
+
column = column_for(table_name, column_name)
|
|
414
|
+
type ||= column.sql_type
|
|
415
|
+
|
|
416
|
+
unless options.key?(:default)
|
|
417
|
+
options[:default] = column.default
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
unless options.key?(:null)
|
|
421
|
+
options[:null] = column.null
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
unless options.key?(:comment)
|
|
425
|
+
options[:comment] = column.comment
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
if options[:collation] == :no_collation
|
|
429
|
+
options.delete(:collation)
|
|
430
|
+
else
|
|
431
|
+
options[:collation] ||= column.collation if text_type?(type)
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
unless options.key?(:auto_increment)
|
|
435
|
+
options[:auto_increment] = column.auto_increment?
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
td = create_table_definition(table_name)
|
|
439
|
+
cd = td.new_column_definition(column.name, type, **options)
|
|
440
|
+
ChangeColumnDefinition.new(cd, column.name)
|
|
441
|
+
end
|
|
442
|
+
|
|
363
443
|
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
|
364
444
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
|
|
365
445
|
rename_column_indexes(table_name, column_name, new_column_name)
|
|
366
446
|
end
|
|
367
447
|
|
|
368
448
|
def add_index(table_name, column_name, **options) # :nodoc:
|
|
449
|
+
create_index = build_create_index_definition(table_name, column_name, **options)
|
|
450
|
+
return unless create_index
|
|
451
|
+
|
|
452
|
+
execute schema_creation.accept(create_index)
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def build_create_index_definition(table_name, column_name, **options) # :nodoc:
|
|
369
456
|
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
|
370
457
|
|
|
371
458
|
return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
|
|
372
459
|
|
|
373
|
-
|
|
374
|
-
execute schema_creation.accept(create_index)
|
|
460
|
+
CreateIndexDefinition.new(index, algorithm)
|
|
375
461
|
end
|
|
376
462
|
|
|
377
463
|
def add_sql_comment!(sql, comment) # :nodoc:
|
|
@@ -384,11 +470,13 @@ module ActiveRecord
|
|
|
384
470
|
|
|
385
471
|
scope = quoted_scope(table_name)
|
|
386
472
|
|
|
387
|
-
|
|
473
|
+
# MySQL returns 1 row for each column of composite foreign keys.
|
|
474
|
+
fk_info = internal_exec_query(<<~SQL, "SCHEMA")
|
|
388
475
|
SELECT fk.referenced_table_name AS 'to_table',
|
|
389
476
|
fk.referenced_column_name AS 'primary_key',
|
|
390
477
|
fk.column_name AS 'column',
|
|
391
478
|
fk.constraint_name AS 'name',
|
|
479
|
+
fk.ordinal_position AS 'position',
|
|
392
480
|
rc.update_rule AS 'on_update',
|
|
393
481
|
rc.delete_rule AS 'on_delete'
|
|
394
482
|
FROM information_schema.referential_constraints rc
|
|
@@ -401,17 +489,24 @@ module ActiveRecord
|
|
|
401
489
|
AND rc.table_name = #{scope[:name]}
|
|
402
490
|
SQL
|
|
403
491
|
|
|
404
|
-
fk_info.
|
|
492
|
+
grouped_fk = fk_info.group_by { |row| row["name"] }.values.each { |group| group.sort_by! { |row| row["position"] } }
|
|
493
|
+
grouped_fk.map do |group|
|
|
494
|
+
row = group.first
|
|
405
495
|
options = {
|
|
406
|
-
column: row["column"],
|
|
407
496
|
name: row["name"],
|
|
408
|
-
|
|
497
|
+
on_update: extract_foreign_key_action(row["on_update"]),
|
|
498
|
+
on_delete: extract_foreign_key_action(row["on_delete"])
|
|
409
499
|
}
|
|
410
500
|
|
|
411
|
-
|
|
412
|
-
|
|
501
|
+
if group.one?
|
|
502
|
+
options[:column] = unquote_identifier(row["column"])
|
|
503
|
+
options[:primary_key] = row["primary_key"]
|
|
504
|
+
else
|
|
505
|
+
options[:column] = group.map { |row| unquote_identifier(row["column"]) }
|
|
506
|
+
options[:primary_key] = group.map { |row| row["primary_key"] }
|
|
507
|
+
end
|
|
413
508
|
|
|
414
|
-
ForeignKeyDefinition.new(table_name, row["to_table"], options)
|
|
509
|
+
ForeignKeyDefinition.new(table_name, unquote_identifier(row["to_table"]), options)
|
|
415
510
|
end
|
|
416
511
|
end
|
|
417
512
|
|
|
@@ -431,14 +526,22 @@ module ActiveRecord
|
|
|
431
526
|
SQL
|
|
432
527
|
sql += " AND cc.table_name = #{scope[:name]}" if mariadb?
|
|
433
528
|
|
|
434
|
-
chk_info =
|
|
529
|
+
chk_info = internal_exec_query(sql, "SCHEMA")
|
|
435
530
|
|
|
436
531
|
chk_info.map do |row|
|
|
437
532
|
options = {
|
|
438
533
|
name: row["name"]
|
|
439
534
|
}
|
|
440
535
|
expression = row["expression"]
|
|
441
|
-
expression = expression[1..-2]
|
|
536
|
+
expression = expression[1..-2] if expression.start_with?("(") && expression.end_with?(")")
|
|
537
|
+
expression = strip_whitespace_characters(expression)
|
|
538
|
+
|
|
539
|
+
unless mariadb?
|
|
540
|
+
# MySQL returns check constraints expression in an already escaped form.
|
|
541
|
+
# This leads to duplicate escaping later (e.g. when the expression is used in the SchemaDumper).
|
|
542
|
+
expression = expression.gsub("\\'", "'")
|
|
543
|
+
end
|
|
544
|
+
|
|
442
545
|
CheckConstraintDefinition.new(table_name, expression, options)
|
|
443
546
|
end
|
|
444
547
|
else
|
|
@@ -536,40 +639,75 @@ module ActiveRecord
|
|
|
536
639
|
end
|
|
537
640
|
|
|
538
641
|
def build_insert_sql(insert) # :nodoc:
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
sql
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
642
|
+
no_op_column = quote_column_name(insert.keys.first)
|
|
643
|
+
|
|
644
|
+
# MySQL 8.0.19 replaces `VALUES(<expression>)` clauses with row and column alias names, see https://dev.mysql.com/worklog/task/?id=6312 .
|
|
645
|
+
# then MySQL 8.0.20 deprecates the `VALUES(<expression>)` see https://dev.mysql.com/worklog/task/?id=13325 .
|
|
646
|
+
if supports_insert_raw_alias_syntax?
|
|
647
|
+
values_alias = quote_table_name("#{insert.model.table_name.parameterize}_values")
|
|
648
|
+
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"
|
|
649
|
+
|
|
650
|
+
if insert.skip_duplicates?
|
|
651
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{values_alias}.#{no_op_column}"
|
|
652
|
+
elsif insert.update_duplicates?
|
|
653
|
+
if insert.raw_update_sql?
|
|
654
|
+
sql = +"INSERT #{insert.into} #{insert.values_list} ON DUPLICATE KEY UPDATE #{insert.raw_update_sql}"
|
|
655
|
+
else
|
|
656
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
|
657
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column}<=>#{values_alias}.#{column}" }
|
|
658
|
+
sql << insert.updatable_columns.map { |column| "#{column}=#{values_alias}.#{column}" }.join(",")
|
|
659
|
+
end
|
|
660
|
+
end
|
|
661
|
+
else
|
|
662
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
|
663
|
+
|
|
664
|
+
if insert.skip_duplicates?
|
|
665
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
|
666
|
+
elsif insert.update_duplicates?
|
|
667
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
|
668
|
+
if insert.raw_update_sql?
|
|
669
|
+
sql << insert.raw_update_sql
|
|
670
|
+
else
|
|
671
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
|
|
672
|
+
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
|
673
|
+
end
|
|
551
674
|
end
|
|
552
675
|
end
|
|
553
676
|
|
|
677
|
+
sql << " RETURNING #{insert.returning}" if insert.returning
|
|
554
678
|
sql
|
|
555
679
|
end
|
|
556
680
|
|
|
557
681
|
def check_version # :nodoc:
|
|
558
682
|
if database_version < "5.5.8"
|
|
559
|
-
raise "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
|
|
683
|
+
raise DatabaseVersionError, "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
|
|
684
|
+
end
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
#--
|
|
688
|
+
# QUOTING ==================================================
|
|
689
|
+
#++
|
|
690
|
+
|
|
691
|
+
# Quotes strings for use in SQL input.
|
|
692
|
+
def quote_string(string)
|
|
693
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |connection|
|
|
694
|
+
connection.escape(string)
|
|
560
695
|
end
|
|
561
696
|
end
|
|
562
697
|
|
|
563
698
|
class << self
|
|
699
|
+
def extended_type_map(default_timezone: nil, emulate_booleans:) # :nodoc:
|
|
700
|
+
super(default_timezone: default_timezone).tap do |m|
|
|
701
|
+
if emulate_booleans
|
|
702
|
+
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
|
|
703
|
+
end
|
|
704
|
+
end
|
|
705
|
+
end
|
|
706
|
+
|
|
564
707
|
private
|
|
565
708
|
def initialize_type_map(m)
|
|
566
709
|
super
|
|
567
710
|
|
|
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
711
|
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
|
574
712
|
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
|
575
713
|
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
|
|
@@ -589,9 +727,6 @@ module ActiveRecord
|
|
|
589
727
|
|
|
590
728
|
m.alias_type %r(year)i, "integer"
|
|
591
729
|
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
730
|
end
|
|
596
731
|
|
|
597
732
|
def register_integer_type(mapping, key, **options)
|
|
@@ -613,31 +748,55 @@ module ActiveRecord
|
|
|
613
748
|
end
|
|
614
749
|
end
|
|
615
750
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
|
|
619
|
-
end
|
|
751
|
+
EXTENDED_TYPE_MAPS = Concurrent::Map.new
|
|
752
|
+
EMULATE_BOOLEANS_TRUE = { emulate_booleans: true }.freeze
|
|
620
753
|
|
|
621
754
|
private
|
|
622
|
-
def
|
|
623
|
-
|
|
755
|
+
def strip_whitespace_characters(expression)
|
|
756
|
+
expression = expression.gsub(/\\n|\\\\/, "")
|
|
757
|
+
expression = expression.gsub(/\s{2,}/, " ")
|
|
758
|
+
expression
|
|
624
759
|
end
|
|
625
760
|
|
|
626
|
-
def
|
|
627
|
-
|
|
628
|
-
|
|
761
|
+
def extended_type_map_key
|
|
762
|
+
if @default_timezone
|
|
763
|
+
{ default_timezone: @default_timezone, emulate_booleans: emulate_booleans }
|
|
764
|
+
elsif emulate_booleans
|
|
765
|
+
EMULATE_BOOLEANS_TRUE
|
|
766
|
+
end
|
|
767
|
+
end
|
|
629
768
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
769
|
+
def handle_warnings(sql)
|
|
770
|
+
return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
|
|
771
|
+
|
|
772
|
+
@affected_rows_before_warnings = @raw_connection.affected_rows
|
|
773
|
+
warning_count = @raw_connection.warning_count
|
|
774
|
+
result = @raw_connection.query("SHOW WARNINGS")
|
|
775
|
+
result = [
|
|
776
|
+
["Warning", nil, "Query had warning_count=#{warning_count} but ‘SHOW WARNINGS’ did not return the warnings. Check MySQL logs or database configuration."],
|
|
777
|
+
] if result.count == 0
|
|
778
|
+
result.each do |level, code, message|
|
|
779
|
+
warning = SQLWarning.new(message, code, level, sql, @pool)
|
|
780
|
+
next if warning_ignored?(warning)
|
|
781
|
+
|
|
782
|
+
ActiveRecord.db_warnings_action.call(warning)
|
|
634
783
|
end
|
|
635
784
|
end
|
|
636
785
|
|
|
786
|
+
def warning_ignored?(warning)
|
|
787
|
+
warning.level == "Note" || super
|
|
788
|
+
end
|
|
789
|
+
|
|
790
|
+
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
|
791
|
+
# made since we established the connection
|
|
792
|
+
def sync_timezone_changes(raw_connection)
|
|
793
|
+
end
|
|
794
|
+
|
|
637
795
|
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
|
|
638
796
|
ER_DB_CREATE_EXISTS = 1007
|
|
639
797
|
ER_FILSORT_ABORT = 1028
|
|
640
798
|
ER_DUP_ENTRY = 1062
|
|
799
|
+
ER_SERVER_SHUTDOWN = 1053
|
|
641
800
|
ER_NOT_NULL_VIOLATION = 1048
|
|
642
801
|
ER_NO_REFERENCED_ROW = 1216
|
|
643
802
|
ER_ROW_IS_REFERENCED = 1217
|
|
@@ -651,69 +810,59 @@ module ActiveRecord
|
|
|
651
810
|
ER_CANNOT_CREATE_TABLE = 1005
|
|
652
811
|
ER_LOCK_WAIT_TIMEOUT = 1205
|
|
653
812
|
ER_QUERY_INTERRUPTED = 1317
|
|
813
|
+
ER_CONNECTION_KILLED = 1927
|
|
814
|
+
CR_SERVER_GONE_ERROR = 2006
|
|
815
|
+
CR_SERVER_LOST = 2013
|
|
654
816
|
ER_QUERY_TIMEOUT = 3024
|
|
655
817
|
ER_FK_INCOMPATIBLE_COLUMNS = 3780
|
|
818
|
+
ER_CLIENT_INTERACTION_TIMEOUT = 4031
|
|
656
819
|
|
|
657
820
|
def translate_exception(exception, message:, sql:, binds:)
|
|
658
821
|
case error_number(exception)
|
|
659
822
|
when nil
|
|
660
823
|
if exception.message.match?(/MySQL client is not connected/i)
|
|
661
|
-
ConnectionNotEstablished.new(exception)
|
|
824
|
+
ConnectionNotEstablished.new(exception, connection_pool: @pool)
|
|
662
825
|
else
|
|
663
826
|
super
|
|
664
827
|
end
|
|
828
|
+
when ER_CONNECTION_KILLED, ER_SERVER_SHUTDOWN, CR_SERVER_GONE_ERROR, CR_SERVER_LOST, ER_CLIENT_INTERACTION_TIMEOUT
|
|
829
|
+
ConnectionFailed.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
665
830
|
when ER_DB_CREATE_EXISTS
|
|
666
|
-
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
|
|
831
|
+
DatabaseAlreadyExists.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
667
832
|
when ER_DUP_ENTRY
|
|
668
|
-
RecordNotUnique.new(message, sql: sql, binds: binds)
|
|
833
|
+
RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
669
834
|
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)
|
|
835
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
671
836
|
when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
|
|
672
|
-
mismatched_foreign_key(message, sql: sql, binds: binds)
|
|
837
|
+
mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
673
838
|
when ER_CANNOT_CREATE_TABLE
|
|
674
839
|
if message.include?("errno: 150")
|
|
675
|
-
mismatched_foreign_key(message, sql: sql, binds: binds)
|
|
840
|
+
mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
676
841
|
else
|
|
677
842
|
super
|
|
678
843
|
end
|
|
679
844
|
when ER_DATA_TOO_LONG
|
|
680
|
-
ValueTooLong.new(message, sql: sql, binds: binds)
|
|
845
|
+
ValueTooLong.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
681
846
|
when ER_OUT_OF_RANGE
|
|
682
|
-
RangeError.new(message, sql: sql, binds: binds)
|
|
847
|
+
RangeError.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
683
848
|
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
|
684
|
-
NotNullViolation.new(message, sql: sql, binds: binds)
|
|
849
|
+
NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
685
850
|
when ER_LOCK_DEADLOCK
|
|
686
|
-
Deadlocked.new(message, sql: sql, binds: binds)
|
|
851
|
+
Deadlocked.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
687
852
|
when ER_LOCK_WAIT_TIMEOUT
|
|
688
|
-
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
|
853
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
689
854
|
when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
|
|
690
|
-
StatementTimeout.new(message, sql: sql, binds: binds)
|
|
855
|
+
StatementTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
691
856
|
when ER_QUERY_INTERRUPTED
|
|
692
|
-
QueryCanceled.new(message, sql: sql, binds: binds)
|
|
857
|
+
QueryCanceled.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
693
858
|
else
|
|
694
859
|
super
|
|
695
860
|
end
|
|
696
861
|
end
|
|
697
862
|
|
|
698
863
|
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
|
-
td = create_table_definition(table_name)
|
|
715
|
-
cd = td.new_column_definition(column.name, type, **options)
|
|
716
|
-
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
|
864
|
+
cd = build_change_column_definition(table_name, column_name, type, **options)
|
|
865
|
+
schema_creation.accept(cd)
|
|
717
866
|
end
|
|
718
867
|
|
|
719
868
|
def rename_column_for_alter(table_name, column_name, new_column_name)
|
|
@@ -727,7 +876,7 @@ module ActiveRecord
|
|
|
727
876
|
comment: column.comment
|
|
728
877
|
}
|
|
729
878
|
|
|
730
|
-
current_type =
|
|
879
|
+
current_type = internal_exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
|
|
731
880
|
td = create_table_definition(table_name)
|
|
732
881
|
cd = td.new_column_definition(new_column_name, current_type, **options)
|
|
733
882
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
|
@@ -745,6 +894,10 @@ module ActiveRecord
|
|
|
745
894
|
"DROP INDEX #{quote_column_name(index_name)}"
|
|
746
895
|
end
|
|
747
896
|
|
|
897
|
+
def supports_insert_raw_alias_syntax?
|
|
898
|
+
!mariadb? && database_version >= "8.0.19"
|
|
899
|
+
end
|
|
900
|
+
|
|
748
901
|
def supports_rename_index?
|
|
749
902
|
if mariadb?
|
|
750
903
|
database_version >= "10.5.2"
|
|
@@ -762,11 +915,9 @@ module ActiveRecord
|
|
|
762
915
|
end
|
|
763
916
|
|
|
764
917
|
def configure_connection
|
|
918
|
+
super
|
|
765
919
|
variables = @config.fetch(:variables, {}).stringify_keys
|
|
766
920
|
|
|
767
|
-
# By default, MySQL 'where id is null' selects the last inserted id; Turn this off.
|
|
768
|
-
variables["sql_auto_is_null"] = 0
|
|
769
|
-
|
|
770
921
|
# Increase timeout so the server doesn't disconnect us.
|
|
771
922
|
wait_timeout = self.class.type_cast_config_to_integer(@config[:wait_timeout])
|
|
772
923
|
wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
|
|
@@ -810,7 +961,7 @@ module ActiveRecord
|
|
|
810
961
|
end.join(", ")
|
|
811
962
|
|
|
812
963
|
# ...and send them all in one query
|
|
813
|
-
|
|
964
|
+
internal_execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}")
|
|
814
965
|
end
|
|
815
966
|
|
|
816
967
|
def column_definitions(table_name) # :nodoc:
|
|
@@ -820,7 +971,7 @@ module ActiveRecord
|
|
|
820
971
|
end
|
|
821
972
|
|
|
822
973
|
def create_table_info(table_name) # :nodoc:
|
|
823
|
-
|
|
974
|
+
internal_exec_query("SHOW CREATE TABLE #{quote_table_name(table_name)}", "SCHEMA").first["Create Table"]
|
|
824
975
|
end
|
|
825
976
|
|
|
826
977
|
def arel_visitor
|
|
@@ -831,18 +982,17 @@ module ActiveRecord
|
|
|
831
982
|
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
|
832
983
|
end
|
|
833
984
|
|
|
834
|
-
def
|
|
985
|
+
def mismatched_foreign_key_details(message:, sql:)
|
|
986
|
+
foreign_key_pat =
|
|
987
|
+
/Referencing column '(\w+)' and referenced/i =~ message ? $1 : '\w+'
|
|
988
|
+
|
|
835
989
|
match = %r/
|
|
836
990
|
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
|
837
|
-
FOREIGN\s+KEY\s*\(`?(?<foreign_key
|
|
991
|
+
FOREIGN\s+KEY\s*\(`?(?<foreign_key>#{foreign_key_pat})`?\)\s*
|
|
838
992
|
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
|
839
993
|
/xmi.match(sql)
|
|
840
994
|
|
|
841
|
-
options = {
|
|
842
|
-
message: message,
|
|
843
|
-
sql: sql,
|
|
844
|
-
binds: binds,
|
|
845
|
-
}
|
|
995
|
+
options = {}
|
|
846
996
|
|
|
847
997
|
if match
|
|
848
998
|
options[:table] = match[:table]
|
|
@@ -852,20 +1002,33 @@ module ActiveRecord
|
|
|
852
1002
|
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
|
853
1003
|
end
|
|
854
1004
|
|
|
855
|
-
|
|
1005
|
+
options
|
|
856
1006
|
end
|
|
857
1007
|
|
|
858
|
-
def
|
|
859
|
-
|
|
860
|
-
|
|
1008
|
+
def mismatched_foreign_key(message, sql:, binds:, connection_pool:)
|
|
1009
|
+
options = {
|
|
1010
|
+
message: message,
|
|
1011
|
+
sql: sql,
|
|
1012
|
+
binds: binds,
|
|
1013
|
+
connection_pool: connection_pool
|
|
1014
|
+
}
|
|
861
1015
|
|
|
862
|
-
|
|
863
|
-
|
|
1016
|
+
if sql
|
|
1017
|
+
options.update mismatched_foreign_key_details(message: message, sql: sql)
|
|
1018
|
+
else
|
|
1019
|
+
options[:query_parser] = ->(sql) { mismatched_foreign_key_details(message: message, sql: sql) }
|
|
1020
|
+
end
|
|
1021
|
+
|
|
1022
|
+
MismatchedForeignKey.new(**options)
|
|
864
1023
|
end
|
|
865
|
-
|
|
866
|
-
|
|
1024
|
+
|
|
1025
|
+
def version_string(full_version_string)
|
|
1026
|
+
if full_version_string && matches = full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)
|
|
1027
|
+
matches[1]
|
|
1028
|
+
else
|
|
1029
|
+
raise DatabaseVersionError, "Unable to parse MySQL version from #{full_version_string.inspect}"
|
|
1030
|
+
end
|
|
867
1031
|
end
|
|
868
|
-
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
|
|
869
1032
|
end
|
|
870
1033
|
end
|
|
871
1034
|
end
|