activerecord 6.1.7 → 7.1.5
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 +2030 -1020
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +1 -11
- data/lib/active_record/associations/association.rb +51 -19
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +40 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +39 -35
- data/lib/active_record/associations/collection_proxy.rb +30 -15
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -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 +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +28 -20
- data/lib/active_record/associations/preloader/association.rb +210 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -14
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +9 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +446 -306
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +78 -26
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +27 -12
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +161 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +65 -31
- data/lib/active_record/base.rb +25 -2
- data/lib/active_record/callbacks.rb +18 -34
- 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 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
- data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
- 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 +39 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
- data/lib/active_record/connection_adapters/pool_config.rb +20 -11
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
- 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/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
- data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
- data/lib/active_record/connection_adapters.rb +9 -6
- data/lib/active_record/connection_handling.rb +108 -137
- data/lib/active_record/core.rb +242 -233
- data/lib/active_record/counter_cache.rb +52 -27
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +88 -16
- data/lib/active_record/database_configurations/url_config.rb +18 -12
- data/lib/active_record/database_configurations.rb +95 -59
- data/lib/active_record/delegated_type.rb +66 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +92 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +154 -63
- data/lib/active_record/errors.rb +172 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -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 +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +147 -86
- data/lib/active_record/future_result.rb +174 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +81 -29
- data/lib/active_record/insert_all.rb +135 -22
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +119 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +37 -22
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- 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 +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +112 -14
- data/lib/active_record/migration/compatibility.rb +233 -46
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +361 -173
- data/lib/active_record/model_schema.rb +125 -101
- data/lib/active_record/nested_attributes.rb +50 -20
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +409 -88
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- data/lib/active_record/query_logs.rb +174 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +29 -6
- data/lib/active_record/railtie.rb +220 -44
- data/lib/active_record/railties/controller_runtime.rb +15 -10
- data/lib/active_record/railties/databases.rake +188 -252
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +248 -81
- data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
- data/lib/active_record/relation/batches.rb +192 -63
- data/lib/active_record/relation/calculations.rb +246 -90
- data/lib/active_record/relation/delegation.rb +28 -14
- data/lib/active_record/relation/finder_methods.rb +108 -51
- data/lib/active_record/relation/merger.rb +22 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +27 -20
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +670 -129
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +20 -3
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +287 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +32 -13
- data/lib/active_record/sanitization.rb +65 -20
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +73 -24
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +10 -8
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +251 -140
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +117 -96
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +48 -27
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -5
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +4 -4
- 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 +51 -6
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +335 -32
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +5 -0
- data/lib/arel/predications.rb +13 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +5 -13
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +16 -3
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +141 -20
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +18 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -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
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +96 -16
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -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
|
|
@@ -31,6 +33,7 @@ module ActiveRecord
|
|
31
33
|
string: { name: "varchar", limit: 255 },
|
32
34
|
text: { name: "text" },
|
33
35
|
integer: { name: "int", limit: 4 },
|
36
|
+
bigint: { name: "bigint" },
|
34
37
|
float: { name: "float", limit: 24 },
|
35
38
|
decimal: { name: "decimal" },
|
36
39
|
datetime: { name: "datetime" },
|
@@ -50,11 +53,37 @@ module ActiveRecord
|
|
50
53
|
end
|
51
54
|
end
|
52
55
|
|
53
|
-
|
54
|
-
|
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
|
55
84
|
end
|
56
85
|
|
57
|
-
def get_database_version
|
86
|
+
def get_database_version # :nodoc:
|
58
87
|
full_version_string = get_full_version
|
59
88
|
version_string = version_string(full_version_string)
|
60
89
|
Version.new(version_string, full_version_string)
|
@@ -80,6 +109,10 @@ module ActiveRecord
|
|
80
109
|
true
|
81
110
|
end
|
82
111
|
|
112
|
+
def supports_restart_db_transaction?
|
113
|
+
true
|
114
|
+
end
|
115
|
+
|
83
116
|
def supports_explain?
|
84
117
|
true
|
85
118
|
end
|
@@ -94,7 +127,7 @@ module ActiveRecord
|
|
94
127
|
|
95
128
|
def supports_check_constraints?
|
96
129
|
if mariadb?
|
97
|
-
database_version >= "10.2.
|
130
|
+
database_version >= "10.3.10" || (database_version < "10.3" && database_version >= "10.2.22")
|
98
131
|
else
|
99
132
|
database_version >= "8.0.16"
|
100
133
|
end
|
@@ -174,7 +207,7 @@ module ActiveRecord
|
|
174
207
|
|
175
208
|
# REFERENTIAL INTEGRITY ====================================
|
176
209
|
|
177
|
-
def disable_referential_integrity
|
210
|
+
def disable_referential_integrity # :nodoc:
|
178
211
|
old = query_value("SELECT @@FOREIGN_KEY_CHECKS")
|
179
212
|
|
180
213
|
begin
|
@@ -185,54 +218,43 @@ module ActiveRecord
|
|
185
218
|
end
|
186
219
|
end
|
187
220
|
|
188
|
-
# CONNECTION MANAGEMENT ====================================
|
189
|
-
|
190
|
-
def clear_cache! # :nodoc:
|
191
|
-
reload_type_map
|
192
|
-
super
|
193
|
-
end
|
194
|
-
|
195
221
|
#--
|
196
222
|
# DATABASE STATEMENTS ======================================
|
197
223
|
#++
|
198
224
|
|
199
|
-
# Executes the SQL statement in the context of this connection.
|
200
|
-
def execute(sql, name = nil)
|
201
|
-
materialize_transactions
|
202
|
-
mark_transaction_written_if_write(sql)
|
203
|
-
|
204
|
-
log(sql, name) do
|
205
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
206
|
-
@connection.query(sql)
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
225
|
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
212
226
|
# to write stuff in an abstract way without concerning ourselves about whether it
|
213
227
|
# needs to be explicitly freed or not.
|
214
|
-
def execute_and_free(sql, name = nil) # :nodoc:
|
215
|
-
|
228
|
+
def execute_and_free(sql, name = nil, async: false) # :nodoc:
|
229
|
+
sql = transform_query(sql)
|
230
|
+
check_if_write_query(sql)
|
231
|
+
|
232
|
+
mark_transaction_written_if_write(sql)
|
233
|
+
yield raw_execute(sql, name, async: async)
|
216
234
|
end
|
217
235
|
|
218
|
-
def begin_db_transaction
|
219
|
-
|
236
|
+
def begin_db_transaction # :nodoc:
|
237
|
+
internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
220
238
|
end
|
221
239
|
|
222
|
-
def begin_isolated_db_transaction(isolation)
|
223
|
-
|
240
|
+
def begin_isolated_db_transaction(isolation) # :nodoc:
|
241
|
+
internal_execute("SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
224
242
|
begin_db_transaction
|
225
243
|
end
|
226
244
|
|
227
|
-
def commit_db_transaction
|
228
|
-
|
245
|
+
def commit_db_transaction # :nodoc:
|
246
|
+
internal_execute("COMMIT", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
229
247
|
end
|
230
248
|
|
231
|
-
def exec_rollback_db_transaction
|
232
|
-
|
249
|
+
def exec_rollback_db_transaction # :nodoc:
|
250
|
+
internal_execute("ROLLBACK", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
233
251
|
end
|
234
252
|
|
235
|
-
def
|
253
|
+
def exec_restart_db_transaction # :nodoc:
|
254
|
+
internal_execute("ROLLBACK AND CHAIN", "TRANSACTION", allow_retry: false, materialize_transactions: true)
|
255
|
+
end
|
256
|
+
|
257
|
+
def empty_insert_statement_value(primary_key = nil) # :nodoc:
|
236
258
|
"VALUES ()"
|
237
259
|
end
|
238
260
|
|
@@ -270,7 +292,7 @@ module ActiveRecord
|
|
270
292
|
#
|
271
293
|
# Example:
|
272
294
|
# drop_database('sebastian_development')
|
273
|
-
def drop_database(name)
|
295
|
+
def drop_database(name) # :nodoc:
|
274
296
|
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
|
275
297
|
end
|
276
298
|
|
@@ -309,11 +331,12 @@ module ActiveRecord
|
|
309
331
|
#
|
310
332
|
# Example:
|
311
333
|
# rename_table('octopuses', 'octopi')
|
312
|
-
def rename_table(table_name, new_name)
|
334
|
+
def rename_table(table_name, new_name, **options)
|
335
|
+
validate_table_length!(new_name) unless options[:_uses_legacy_table_name]
|
313
336
|
schema_cache.clear_data_source_cache!(table_name.to_s)
|
314
337
|
schema_cache.clear_data_source_cache!(new_name.to_s)
|
315
338
|
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
316
|
-
rename_table_indexes(table_name, new_name)
|
339
|
+
rename_table_indexes(table_name, new_name, **options)
|
317
340
|
end
|
318
341
|
|
319
342
|
# Drops a table from the database.
|
@@ -346,12 +369,21 @@ module ActiveRecord
|
|
346
369
|
end
|
347
370
|
end
|
348
371
|
|
349
|
-
def change_column_default(table_name, column_name, default_or_changes)
|
372
|
+
def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
|
373
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{change_column_default_for_alter(table_name, column_name, default_or_changes)}"
|
374
|
+
end
|
375
|
+
|
376
|
+
def build_change_column_default_definition(table_name, column_name, default_or_changes) # :nodoc:
|
377
|
+
column = column_for(table_name, column_name)
|
378
|
+
return unless column
|
379
|
+
|
350
380
|
default = extract_new_default_value(default_or_changes)
|
351
|
-
|
381
|
+
ChangeColumnDefaultDefinition.new(column, default)
|
352
382
|
end
|
353
383
|
|
354
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
384
|
+
def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
|
385
|
+
validate_change_column_null_argument!(null)
|
386
|
+
|
355
387
|
unless null || default.nil?
|
356
388
|
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
357
389
|
end
|
@@ -364,22 +396,64 @@ module ActiveRecord
|
|
364
396
|
change_column table_name, column_name, nil, comment: comment
|
365
397
|
end
|
366
398
|
|
367
|
-
def change_column(table_name, column_name, type, **options)
|
399
|
+
def change_column(table_name, column_name, type, **options) # :nodoc:
|
368
400
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
|
369
401
|
end
|
370
402
|
|
371
|
-
|
403
|
+
# Builds a ChangeColumnDefinition object.
|
404
|
+
#
|
405
|
+
# This definition object contains information about the column change that would occur
|
406
|
+
# if the same arguments were passed to #change_column. See #change_column for information about
|
407
|
+
# passing a +table_name+, +column_name+, +type+ and other options that can be passed.
|
408
|
+
def build_change_column_definition(table_name, column_name, type, **options) # :nodoc:
|
409
|
+
column = column_for(table_name, column_name)
|
410
|
+
type ||= column.sql_type
|
411
|
+
|
412
|
+
unless options.key?(:default)
|
413
|
+
options[:default] = column.default
|
414
|
+
end
|
415
|
+
|
416
|
+
unless options.key?(:null)
|
417
|
+
options[:null] = column.null
|
418
|
+
end
|
419
|
+
|
420
|
+
unless options.key?(:comment)
|
421
|
+
options[:comment] = column.comment
|
422
|
+
end
|
423
|
+
|
424
|
+
if options[:collation] == :no_collation
|
425
|
+
options.delete(:collation)
|
426
|
+
else
|
427
|
+
options[:collation] ||= column.collation if text_type?(type)
|
428
|
+
end
|
429
|
+
|
430
|
+
unless options.key?(:auto_increment)
|
431
|
+
options[:auto_increment] = column.auto_increment?
|
432
|
+
end
|
433
|
+
|
434
|
+
td = create_table_definition(table_name)
|
435
|
+
cd = td.new_column_definition(column.name, type, **options)
|
436
|
+
ChangeColumnDefinition.new(cd, column.name)
|
437
|
+
end
|
438
|
+
|
439
|
+
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
372
440
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
|
373
441
|
rename_column_indexes(table_name, column_name, new_column_name)
|
374
442
|
end
|
375
443
|
|
376
|
-
def add_index(table_name, column_name, **options)
|
444
|
+
def add_index(table_name, column_name, **options) # :nodoc:
|
445
|
+
create_index = build_create_index_definition(table_name, column_name, **options)
|
446
|
+
return unless create_index
|
447
|
+
|
448
|
+
execute schema_creation.accept(create_index)
|
449
|
+
end
|
450
|
+
|
451
|
+
def build_create_index_definition(table_name, column_name, **options) # :nodoc:
|
377
452
|
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
378
453
|
|
379
454
|
return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
|
380
455
|
|
381
|
-
|
382
|
-
execute schema_creation.accept(create_index)
|
456
|
+
CreateIndexDefinition.new(index, algorithm)
|
383
457
|
end
|
384
458
|
|
385
459
|
def add_sql_comment!(sql, comment) # :nodoc:
|
@@ -392,11 +466,13 @@ module ActiveRecord
|
|
392
466
|
|
393
467
|
scope = quoted_scope(table_name)
|
394
468
|
|
395
|
-
|
469
|
+
# MySQL returns 1 row for each column of composite foreign keys.
|
470
|
+
fk_info = internal_exec_query(<<~SQL, "SCHEMA")
|
396
471
|
SELECT fk.referenced_table_name AS 'to_table',
|
397
472
|
fk.referenced_column_name AS 'primary_key',
|
398
473
|
fk.column_name AS 'column',
|
399
474
|
fk.constraint_name AS 'name',
|
475
|
+
fk.ordinal_position AS 'position',
|
400
476
|
rc.update_rule AS 'on_update',
|
401
477
|
rc.delete_rule AS 'on_delete'
|
402
478
|
FROM information_schema.referential_constraints rc
|
@@ -409,17 +485,24 @@ module ActiveRecord
|
|
409
485
|
AND rc.table_name = #{scope[:name]}
|
410
486
|
SQL
|
411
487
|
|
412
|
-
fk_info.
|
488
|
+
grouped_fk = fk_info.group_by { |row| row["name"] }.values.each { |group| group.sort_by! { |row| row["position"] } }
|
489
|
+
grouped_fk.map do |group|
|
490
|
+
row = group.first
|
413
491
|
options = {
|
414
|
-
column: row["column"],
|
415
492
|
name: row["name"],
|
416
|
-
|
493
|
+
on_update: extract_foreign_key_action(row["on_update"]),
|
494
|
+
on_delete: extract_foreign_key_action(row["on_delete"])
|
417
495
|
}
|
418
496
|
|
419
|
-
|
420
|
-
|
497
|
+
if group.one?
|
498
|
+
options[:column] = unquote_identifier(row["column"])
|
499
|
+
options[:primary_key] = row["primary_key"]
|
500
|
+
else
|
501
|
+
options[:column] = group.map { |row| unquote_identifier(row["column"]) }
|
502
|
+
options[:primary_key] = group.map { |row| row["primary_key"] }
|
503
|
+
end
|
421
504
|
|
422
|
-
ForeignKeyDefinition.new(table_name, row["to_table"], options)
|
505
|
+
ForeignKeyDefinition.new(table_name, unquote_identifier(row["to_table"]), options)
|
423
506
|
end
|
424
507
|
end
|
425
508
|
|
@@ -427,7 +510,7 @@ module ActiveRecord
|
|
427
510
|
if supports_check_constraints?
|
428
511
|
scope = quoted_scope(table_name)
|
429
512
|
|
430
|
-
|
513
|
+
sql = <<~SQL
|
431
514
|
SELECT cc.constraint_name AS 'name',
|
432
515
|
cc.check_clause AS 'expression'
|
433
516
|
FROM information_schema.check_constraints cc
|
@@ -437,13 +520,24 @@ module ActiveRecord
|
|
437
520
|
AND tc.table_name = #{scope[:name]}
|
438
521
|
AND cc.constraint_schema = #{scope[:schema]}
|
439
522
|
SQL
|
523
|
+
sql += " AND cc.table_name = #{scope[:name]}" if mariadb?
|
524
|
+
|
525
|
+
chk_info = internal_exec_query(sql, "SCHEMA")
|
440
526
|
|
441
527
|
chk_info.map do |row|
|
442
528
|
options = {
|
443
529
|
name: row["name"]
|
444
530
|
}
|
445
531
|
expression = row["expression"]
|
446
|
-
expression = expression[1..-2]
|
532
|
+
expression = expression[1..-2] if expression.start_with?("(") && expression.end_with?(")")
|
533
|
+
expression = strip_whitespace_characters(expression)
|
534
|
+
|
535
|
+
unless mariadb?
|
536
|
+
# MySQL returns check constraints expression in an already escaped form.
|
537
|
+
# This leads to duplicate escaping later (e.g. when the expression is used in the SchemaDumper).
|
538
|
+
expression = expression.gsub("\\'", "'")
|
539
|
+
end
|
540
|
+
|
447
541
|
CheckConstraintDefinition.new(table_name, expression, options)
|
448
542
|
end
|
449
543
|
else
|
@@ -541,15 +635,39 @@ module ActiveRecord
|
|
541
635
|
end
|
542
636
|
|
543
637
|
def build_insert_sql(insert) # :nodoc:
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
sql
|
551
|
-
|
552
|
-
|
638
|
+
no_op_column = quote_column_name(insert.keys.first)
|
639
|
+
|
640
|
+
# MySQL 8.0.19 replaces `VALUES(<expression>)` clauses with row and column alias names, see https://dev.mysql.com/worklog/task/?id=6312 .
|
641
|
+
# then MySQL 8.0.20 deprecates the `VALUES(<expression>)` see https://dev.mysql.com/worklog/task/?id=13325 .
|
642
|
+
if supports_insert_raw_alias_syntax?
|
643
|
+
values_alias = quote_table_name("#{insert.model.table_name}_values")
|
644
|
+
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"
|
645
|
+
|
646
|
+
if insert.skip_duplicates?
|
647
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{values_alias}.#{no_op_column}"
|
648
|
+
elsif insert.update_duplicates?
|
649
|
+
if insert.raw_update_sql?
|
650
|
+
sql = +"INSERT #{insert.into} #{insert.values_list} ON DUPLICATE KEY UPDATE #{insert.raw_update_sql}"
|
651
|
+
else
|
652
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
653
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column}<=>#{values_alias}.#{column}" }
|
654
|
+
sql << insert.updatable_columns.map { |column| "#{column}=#{values_alias}.#{column}" }.join(",")
|
655
|
+
end
|
656
|
+
end
|
657
|
+
else
|
658
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
659
|
+
|
660
|
+
if insert.skip_duplicates?
|
661
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
662
|
+
elsif insert.update_duplicates?
|
663
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
664
|
+
if insert.raw_update_sql?
|
665
|
+
sql << insert.raw_update_sql
|
666
|
+
else
|
667
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
|
668
|
+
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
669
|
+
end
|
670
|
+
end
|
553
671
|
end
|
554
672
|
|
555
673
|
sql
|
@@ -561,58 +679,99 @@ module ActiveRecord
|
|
561
679
|
end
|
562
680
|
end
|
563
681
|
|
564
|
-
|
565
|
-
def
|
566
|
-
super
|
682
|
+
class << self
|
683
|
+
def extended_type_map(default_timezone: nil, emulate_booleans:) # :nodoc:
|
684
|
+
super(default_timezone: default_timezone).tap do |m|
|
685
|
+
if emulate_booleans
|
686
|
+
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
|
687
|
+
end
|
688
|
+
end
|
689
|
+
end
|
567
690
|
|
568
|
-
|
569
|
-
|
570
|
-
|
691
|
+
private
|
692
|
+
def initialize_type_map(m)
|
693
|
+
super
|
694
|
+
|
695
|
+
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
696
|
+
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
697
|
+
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
|
698
|
+
m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
|
699
|
+
m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
|
700
|
+
m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
|
701
|
+
m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
|
702
|
+
m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
|
703
|
+
m.register_type %r(^float)i, Type::Float.new(limit: 24)
|
704
|
+
m.register_type %r(^double)i, Type::Float.new(limit: 53)
|
705
|
+
|
706
|
+
register_integer_type m, %r(^bigint)i, limit: 8
|
707
|
+
register_integer_type m, %r(^int)i, limit: 4
|
708
|
+
register_integer_type m, %r(^mediumint)i, limit: 3
|
709
|
+
register_integer_type m, %r(^smallint)i, limit: 2
|
710
|
+
register_integer_type m, %r(^tinyint)i, limit: 1
|
711
|
+
|
712
|
+
m.alias_type %r(year)i, "integer"
|
713
|
+
m.alias_type %r(bit)i, "binary"
|
571
714
|
end
|
572
715
|
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
register_integer_type m, %r(^mediumint)i, limit: 3
|
587
|
-
register_integer_type m, %r(^smallint)i, limit: 2
|
588
|
-
register_integer_type m, %r(^tinyint)i, limit: 1
|
589
|
-
|
590
|
-
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
|
591
|
-
m.alias_type %r(year)i, "integer"
|
592
|
-
m.alias_type %r(bit)i, "binary"
|
593
|
-
|
594
|
-
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
|
595
|
-
m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
|
596
|
-
end
|
597
|
-
|
598
|
-
def register_integer_type(mapping, key, **options)
|
599
|
-
mapping.register_type(key) do |sql_type|
|
600
|
-
if /\bunsigned\b/.match?(sql_type)
|
601
|
-
Type::UnsignedInteger.new(**options)
|
716
|
+
def register_integer_type(mapping, key, **options)
|
717
|
+
mapping.register_type(key) do |sql_type|
|
718
|
+
if /\bunsigned\b/.match?(sql_type)
|
719
|
+
Type::UnsignedInteger.new(**options)
|
720
|
+
else
|
721
|
+
Type::Integer.new(**options)
|
722
|
+
end
|
723
|
+
end
|
724
|
+
end
|
725
|
+
|
726
|
+
def extract_precision(sql_type)
|
727
|
+
if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
|
728
|
+
super || 0
|
602
729
|
else
|
603
|
-
|
730
|
+
super
|
604
731
|
end
|
605
732
|
end
|
733
|
+
end
|
734
|
+
|
735
|
+
EXTENDED_TYPE_MAPS = Concurrent::Map.new
|
736
|
+
EMULATE_BOOLEANS_TRUE = { emulate_booleans: true }.freeze
|
737
|
+
|
738
|
+
private
|
739
|
+
def strip_whitespace_characters(expression)
|
740
|
+
expression = expression.gsub(/\\n|\\\\/, "")
|
741
|
+
expression = expression.gsub(/\s{2,}/, " ")
|
742
|
+
expression
|
743
|
+
end
|
744
|
+
|
745
|
+
def extended_type_map_key
|
746
|
+
if @default_timezone
|
747
|
+
{ default_timezone: @default_timezone, emulate_booleans: emulate_booleans }
|
748
|
+
elsif emulate_booleans
|
749
|
+
EMULATE_BOOLEANS_TRUE
|
750
|
+
end
|
606
751
|
end
|
607
752
|
|
608
|
-
def
|
609
|
-
if
|
610
|
-
|
611
|
-
|
612
|
-
|
753
|
+
def handle_warnings(sql)
|
754
|
+
return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
|
755
|
+
|
756
|
+
@affected_rows_before_warnings = @raw_connection.affected_rows
|
757
|
+
result = @raw_connection.query("SHOW WARNINGS")
|
758
|
+
result.each do |level, code, message|
|
759
|
+
warning = SQLWarning.new(message, code, level, sql, @pool)
|
760
|
+
next if warning_ignored?(warning)
|
761
|
+
|
762
|
+
ActiveRecord.db_warnings_action.call(warning)
|
613
763
|
end
|
614
764
|
end
|
615
765
|
|
766
|
+
def warning_ignored?(warning)
|
767
|
+
warning.level == "Note" || super
|
768
|
+
end
|
769
|
+
|
770
|
+
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
771
|
+
# made since we established the connection
|
772
|
+
def sync_timezone_changes(raw_connection)
|
773
|
+
end
|
774
|
+
|
616
775
|
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
|
617
776
|
ER_DB_CREATE_EXISTS = 1007
|
618
777
|
ER_FILSORT_ABORT = 1028
|
@@ -630,69 +789,59 @@ module ActiveRecord
|
|
630
789
|
ER_CANNOT_CREATE_TABLE = 1005
|
631
790
|
ER_LOCK_WAIT_TIMEOUT = 1205
|
632
791
|
ER_QUERY_INTERRUPTED = 1317
|
792
|
+
ER_CONNECTION_KILLED = 1927
|
793
|
+
CR_SERVER_GONE_ERROR = 2006
|
794
|
+
CR_SERVER_LOST = 2013
|
633
795
|
ER_QUERY_TIMEOUT = 3024
|
634
796
|
ER_FK_INCOMPATIBLE_COLUMNS = 3780
|
797
|
+
ER_CLIENT_INTERACTION_TIMEOUT = 4031
|
635
798
|
|
636
799
|
def translate_exception(exception, message:, sql:, binds:)
|
637
800
|
case error_number(exception)
|
638
801
|
when nil
|
639
802
|
if exception.message.match?(/MySQL client is not connected/i)
|
640
|
-
ConnectionNotEstablished.new(exception)
|
803
|
+
ConnectionNotEstablished.new(exception, connection_pool: @pool)
|
641
804
|
else
|
642
805
|
super
|
643
806
|
end
|
807
|
+
when ER_CONNECTION_KILLED, CR_SERVER_GONE_ERROR, CR_SERVER_LOST, ER_CLIENT_INTERACTION_TIMEOUT
|
808
|
+
ConnectionFailed.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
644
809
|
when ER_DB_CREATE_EXISTS
|
645
|
-
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
|
810
|
+
DatabaseAlreadyExists.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
646
811
|
when ER_DUP_ENTRY
|
647
|
-
RecordNotUnique.new(message, sql: sql, binds: binds)
|
812
|
+
RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
648
813
|
when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
|
649
|
-
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
814
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
650
815
|
when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
|
651
|
-
mismatched_foreign_key(message, sql: sql, binds: binds)
|
816
|
+
mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
|
652
817
|
when ER_CANNOT_CREATE_TABLE
|
653
818
|
if message.include?("errno: 150")
|
654
|
-
mismatched_foreign_key(message, sql: sql, binds: binds)
|
819
|
+
mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
|
655
820
|
else
|
656
821
|
super
|
657
822
|
end
|
658
823
|
when ER_DATA_TOO_LONG
|
659
|
-
ValueTooLong.new(message, sql: sql, binds: binds)
|
824
|
+
ValueTooLong.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
660
825
|
when ER_OUT_OF_RANGE
|
661
|
-
RangeError.new(message, sql: sql, binds: binds)
|
826
|
+
RangeError.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
662
827
|
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
663
|
-
NotNullViolation.new(message, sql: sql, binds: binds)
|
828
|
+
NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
664
829
|
when ER_LOCK_DEADLOCK
|
665
|
-
Deadlocked.new(message, sql: sql, binds: binds)
|
830
|
+
Deadlocked.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
666
831
|
when ER_LOCK_WAIT_TIMEOUT
|
667
|
-
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
832
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
668
833
|
when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
|
669
|
-
StatementTimeout.new(message, sql: sql, binds: binds)
|
834
|
+
StatementTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
670
835
|
when ER_QUERY_INTERRUPTED
|
671
|
-
QueryCanceled.new(message, sql: sql, binds: binds)
|
836
|
+
QueryCanceled.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
672
837
|
else
|
673
838
|
super
|
674
839
|
end
|
675
840
|
end
|
676
841
|
|
677
842
|
def change_column_for_alter(table_name, column_name, type, **options)
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
unless options.key?(:default)
|
682
|
-
options[:default] = column.default
|
683
|
-
end
|
684
|
-
|
685
|
-
unless options.key?(:null)
|
686
|
-
options[:null] = column.null
|
687
|
-
end
|
688
|
-
|
689
|
-
unless options.key?(:comment)
|
690
|
-
options[:comment] = column.comment
|
691
|
-
end
|
692
|
-
|
693
|
-
td = create_table_definition(table_name)
|
694
|
-
cd = td.new_column_definition(column.name, type, **options)
|
695
|
-
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
843
|
+
cd = build_change_column_definition(table_name, column_name, type, **options)
|
844
|
+
schema_creation.accept(cd)
|
696
845
|
end
|
697
846
|
|
698
847
|
def rename_column_for_alter(table_name, column_name, new_column_name)
|
@@ -706,7 +855,7 @@ module ActiveRecord
|
|
706
855
|
comment: column.comment
|
707
856
|
}
|
708
857
|
|
709
|
-
current_type =
|
858
|
+
current_type = internal_exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
|
710
859
|
td = create_table_definition(table_name)
|
711
860
|
cd = td.new_column_definition(new_column_name, current_type, **options)
|
712
861
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
@@ -724,6 +873,10 @@ module ActiveRecord
|
|
724
873
|
"DROP INDEX #{quote_column_name(index_name)}"
|
725
874
|
end
|
726
875
|
|
876
|
+
def supports_insert_raw_alias_syntax?
|
877
|
+
!mariadb? && database_version >= "8.0.19"
|
878
|
+
end
|
879
|
+
|
727
880
|
def supports_rename_index?
|
728
881
|
if mariadb?
|
729
882
|
database_version >= "10.5.2"
|
@@ -743,9 +896,6 @@ module ActiveRecord
|
|
743
896
|
def configure_connection
|
744
897
|
variables = @config.fetch(:variables, {}).stringify_keys
|
745
898
|
|
746
|
-
# By default, MySQL 'where id is null' selects the last inserted id; Turn this off.
|
747
|
-
variables["sql_auto_is_null"] = 0
|
748
|
-
|
749
899
|
# Increase timeout so the server doesn't disconnect us.
|
750
900
|
wait_timeout = self.class.type_cast_config_to_integer(@config[:wait_timeout])
|
751
901
|
wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
|
@@ -780,17 +930,16 @@ module ActiveRecord
|
|
780
930
|
end
|
781
931
|
|
782
932
|
# Gather up all of the SET variables...
|
783
|
-
variable_assignments = variables.
|
933
|
+
variable_assignments = variables.filter_map do |k, v|
|
784
934
|
if defaults.include?(v)
|
785
935
|
"@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
|
786
936
|
elsif !v.nil?
|
787
937
|
"@@SESSION.#{k} = #{quote(v)}"
|
788
938
|
end
|
789
|
-
|
790
|
-
end.compact.join(", ")
|
939
|
+
end.join(", ")
|
791
940
|
|
792
941
|
# ...and send them all in one query
|
793
|
-
|
942
|
+
internal_execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}")
|
794
943
|
end
|
795
944
|
|
796
945
|
def column_definitions(table_name) # :nodoc:
|
@@ -800,7 +949,7 @@ module ActiveRecord
|
|
800
949
|
end
|
801
950
|
|
802
951
|
def create_table_info(table_name) # :nodoc:
|
803
|
-
|
952
|
+
internal_exec_query("SHOW CREATE TABLE #{quote_table_name(table_name)}", "SCHEMA").first["Create Table"]
|
804
953
|
end
|
805
954
|
|
806
955
|
def arel_visitor
|
@@ -811,18 +960,17 @@ module ActiveRecord
|
|
811
960
|
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
812
961
|
end
|
813
962
|
|
814
|
-
def
|
963
|
+
def mismatched_foreign_key_details(message:, sql:)
|
964
|
+
foreign_key_pat =
|
965
|
+
/Referencing column '(\w+)' and referenced/i =~ message ? $1 : '\w+'
|
966
|
+
|
815
967
|
match = %r/
|
816
968
|
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
817
|
-
FOREIGN\s+KEY\s*\(`?(?<foreign_key
|
969
|
+
FOREIGN\s+KEY\s*\(`?(?<foreign_key>#{foreign_key_pat})`?\)\s*
|
818
970
|
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
819
971
|
/xmi.match(sql)
|
820
972
|
|
821
|
-
options = {
|
822
|
-
message: message,
|
823
|
-
sql: sql,
|
824
|
-
binds: binds,
|
825
|
-
}
|
973
|
+
options = {}
|
826
974
|
|
827
975
|
if match
|
828
976
|
options[:table] = match[:table]
|
@@ -832,24 +980,29 @@ module ActiveRecord
|
|
832
980
|
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
833
981
|
end
|
834
982
|
|
835
|
-
|
983
|
+
options
|
836
984
|
end
|
837
985
|
|
838
|
-
def
|
839
|
-
|
840
|
-
|
986
|
+
def mismatched_foreign_key(message, sql:, binds:, connection_pool:)
|
987
|
+
options = {
|
988
|
+
message: message,
|
989
|
+
sql: sql,
|
990
|
+
binds: binds,
|
991
|
+
connection_pool: connection_pool
|
992
|
+
}
|
841
993
|
|
842
|
-
|
843
|
-
|
844
|
-
|
994
|
+
if sql
|
995
|
+
options.update mismatched_foreign_key_details(message: message, sql: sql)
|
996
|
+
else
|
997
|
+
options[:query_parser] = ->(sql) { mismatched_foreign_key_details(message: message, sql: sql) }
|
998
|
+
end
|
845
999
|
|
846
|
-
|
847
|
-
Type::ImmutableString.new(true: "1", false: "0", **args)
|
1000
|
+
MismatchedForeignKey.new(**options)
|
848
1001
|
end
|
849
|
-
|
850
|
-
|
1002
|
+
|
1003
|
+
def version_string(full_version_string)
|
1004
|
+
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
851
1005
|
end
|
852
|
-
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
|
853
1006
|
end
|
854
1007
|
end
|
855
1008
|
end
|