activerecord 5.2.8.1 → 6.1.6.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1255 -596
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +9 -8
- data/lib/active_record/association_relation.rb +30 -10
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +100 -41
- data/lib/active_record/associations/association_scope.rb +23 -21
- data/lib/active_record/associations/belongs_to_association.rb +55 -48
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
- data/lib/active_record/associations/builder/association.rb +45 -22
- data/lib/active_record/associations/builder/belongs_to.rb +29 -59
- data/lib/active_record/associations/builder/collection_association.rb +8 -17
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -2
- data/lib/active_record/associations/builder/has_one.rb +33 -2
- data/lib/active_record/associations/builder/singular_association.rb +3 -1
- data/lib/active_record/associations/collection_association.rb +44 -34
- data/lib/active_record/associations/collection_proxy.rb +25 -21
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +26 -13
- data/lib/active_record/associations/has_many_through_association.rb +24 -18
- data/lib/active_record/associations/has_one_association.rb +43 -31
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
- data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +91 -60
- data/lib/active_record/associations/preloader/association.rb +69 -43
- data/lib/active_record/associations/preloader/through_association.rb +49 -40
- data/lib/active_record/associations/preloader.rb +47 -34
- data/lib/active_record/associations/singular_association.rb +3 -17
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +137 -25
- data/lib/active_record/attribute_assignment.rb +17 -19
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -40
- data/lib/active_record/attribute_methods/primary_key.rb +20 -25
- data/lib/active_record/attribute_methods/query.rb +4 -8
- data/lib/active_record/attribute_methods/read.rb +14 -56
- data/lib/active_record/attribute_methods/serialization.rb +12 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +18 -34
- data/lib/active_record/attribute_methods.rb +81 -143
- data/lib/active_record/attributes.rb +46 -9
- data/lib/active_record/autosave_association.rb +57 -42
- data/lib/active_record/base.rb +4 -17
- data/lib/active_record/callbacks.rb +158 -43
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +211 -90
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
- data/lib/active_record/connection_adapters/abstract/transaction.rb +167 -69
- data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -99
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
- data/lib/active_record/connection_adapters/column.rb +30 -12
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +88 -32
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +142 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -120
- data/lib/active_record/connection_adapters/schema_cache.rb +159 -21
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +293 -33
- data/lib/active_record/core.rb +333 -98
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/database_configurations.rb +273 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +108 -36
- data/lib/active_record/errors.rb +62 -19
- data/lib/active_record/explain.rb +10 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +32 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +200 -481
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +53 -24
- data/lib/active_record/insert_all.rb +212 -0
- data/lib/active_record/integration.rb +67 -17
- data/lib/active_record/internal_metadata.rb +28 -9
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +37 -23
- data/lib/active_record/locking/pessimistic.rb +9 -5
- data/lib/active_record/log_subscriber.rb +35 -35
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +96 -44
- data/lib/active_record/migration/compatibility.rb +145 -64
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +206 -157
- data/lib/active_record/model_schema.rb +148 -22
- data/lib/active_record/nested_attributes.rb +4 -7
- data/lib/active_record/no_touching.rb +8 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +267 -59
- data/lib/active_record/query_cache.rb +21 -4
- data/lib/active_record/querying.rb +40 -23
- data/lib/active_record/railtie.rb +116 -59
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +411 -80
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +109 -93
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +44 -35
- data/lib/active_record/relation/calculations.rb +157 -90
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +64 -39
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +32 -40
- data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +62 -45
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +476 -187
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +9 -9
- data/lib/active_record/relation/where_clause.rb +115 -62
- data/lib/active_record/relation.rb +379 -115
- data/lib/active_record/result.rb +64 -38
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +22 -41
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +54 -9
- data/lib/active_record/schema_migration.rb +7 -9
- data/lib/active_record/scoping/default.rb +4 -8
- data/lib/active_record/scoping/named.rb +17 -24
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +49 -6
- data/lib/active_record/store.rb +88 -9
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -43
- data/lib/active_record/tasks/database_tasks.rb +277 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
- data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +287 -0
- data/lib/active_record/timestamp.rb +43 -32
- data/lib/active_record/touch_later.rb +23 -22
- data/lib/active_record/transactions.rb +62 -118
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +10 -5
- data/lib/active_record/type_caster/connection.rb +15 -15
- data/lib/active_record/type_caster/map.rb +8 -8
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +38 -30
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record.rb +13 -12
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +15 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +70 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
- data/lib/rails/generators/active_record/migration.rb +19 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +116 -30
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
- data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -11,8 +11,6 @@ require "active_record/connection_adapters/mysql/schema_dumper"
|
|
11
11
|
require "active_record/connection_adapters/mysql/schema_statements"
|
12
12
|
require "active_record/connection_adapters/mysql/type_metadata"
|
13
13
|
|
14
|
-
require "active_support/core_ext/string/strip"
|
15
|
-
|
16
14
|
module ActiveRecord
|
17
15
|
module ConnectionAdapters
|
18
16
|
class AbstractMysqlAdapter < AbstractAdapter
|
@@ -31,7 +29,7 @@ module ActiveRecord
|
|
31
29
|
NATIVE_DATABASE_TYPES = {
|
32
30
|
primary_key: "bigint auto_increment PRIMARY KEY",
|
33
31
|
string: { name: "varchar", limit: 255 },
|
34
|
-
text: { name: "text"
|
32
|
+
text: { name: "text" },
|
35
33
|
integer: { name: "int", limit: 4 },
|
36
34
|
float: { name: "float", limit: 24 },
|
37
35
|
decimal: { name: "decimal" },
|
@@ -39,41 +37,43 @@ module ActiveRecord
|
|
39
37
|
timestamp: { name: "timestamp" },
|
40
38
|
time: { name: "time" },
|
41
39
|
date: { name: "date" },
|
42
|
-
binary: { name: "blob"
|
40
|
+
binary: { name: "blob" },
|
41
|
+
blob: { name: "blob" },
|
43
42
|
boolean: { name: "tinyint", limit: 1 },
|
44
43
|
json: { name: "json" },
|
45
44
|
}
|
46
45
|
|
47
46
|
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
48
|
-
private
|
49
|
-
stmt
|
50
|
-
|
47
|
+
private
|
48
|
+
def dealloc(stmt)
|
49
|
+
stmt.close
|
50
|
+
end
|
51
51
|
end
|
52
52
|
|
53
53
|
def initialize(connection, logger, connection_options, config)
|
54
54
|
super(connection, logger, config)
|
55
|
-
|
56
|
-
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
|
57
|
-
|
58
|
-
if version < "5.1.10"
|
59
|
-
raise "Your version of MySQL (#{version_string}) is too old. Active Record supports MySQL >= 5.1.10."
|
60
|
-
end
|
61
55
|
end
|
62
56
|
|
63
|
-
def
|
64
|
-
|
57
|
+
def get_database_version #:nodoc:
|
58
|
+
full_version_string = get_full_version
|
59
|
+
version_string = version_string(full_version_string)
|
60
|
+
Version.new(version_string, full_version_string)
|
65
61
|
end
|
66
62
|
|
67
63
|
def mariadb? # :nodoc:
|
68
64
|
/mariadb/i.match?(full_version)
|
69
65
|
end
|
70
66
|
|
71
|
-
def supports_bulk_alter?
|
67
|
+
def supports_bulk_alter?
|
72
68
|
true
|
73
69
|
end
|
74
70
|
|
75
71
|
def supports_index_sort_order?
|
76
|
-
!mariadb? &&
|
72
|
+
!mariadb? && database_version >= "8.0.1"
|
73
|
+
end
|
74
|
+
|
75
|
+
def supports_expression_index?
|
76
|
+
!mariadb? && database_version >= "8.0.13"
|
77
77
|
end
|
78
78
|
|
79
79
|
def supports_transaction_isolation?
|
@@ -92,23 +92,36 @@ module ActiveRecord
|
|
92
92
|
true
|
93
93
|
end
|
94
94
|
|
95
|
+
def supports_check_constraints?
|
96
|
+
if mariadb?
|
97
|
+
database_version >= "10.2.1"
|
98
|
+
else
|
99
|
+
database_version >= "8.0.16"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
95
103
|
def supports_views?
|
96
104
|
true
|
97
105
|
end
|
98
106
|
|
99
107
|
def supports_datetime_with_precision?
|
100
|
-
|
101
|
-
version >= "5.3.0"
|
102
|
-
else
|
103
|
-
version >= "5.6.4"
|
104
|
-
end
|
108
|
+
mariadb? || database_version >= "5.6.4"
|
105
109
|
end
|
106
110
|
|
107
111
|
def supports_virtual_columns?
|
112
|
+
mariadb? || database_version >= "5.7.5"
|
113
|
+
end
|
114
|
+
|
115
|
+
# See https://dev.mysql.com/doc/refman/en/optimizer-hints.html for more details.
|
116
|
+
def supports_optimizer_hints?
|
117
|
+
!mariadb? && database_version >= "5.7.7"
|
118
|
+
end
|
119
|
+
|
120
|
+
def supports_common_table_expressions?
|
108
121
|
if mariadb?
|
109
|
-
|
122
|
+
database_version >= "10.2.1"
|
110
123
|
else
|
111
|
-
|
124
|
+
database_version >= "8.0.1"
|
112
125
|
end
|
113
126
|
end
|
114
127
|
|
@@ -116,6 +129,14 @@ module ActiveRecord
|
|
116
129
|
true
|
117
130
|
end
|
118
131
|
|
132
|
+
def supports_insert_on_duplicate_skip?
|
133
|
+
true
|
134
|
+
end
|
135
|
+
|
136
|
+
def supports_insert_on_duplicate_update?
|
137
|
+
true
|
138
|
+
end
|
139
|
+
|
119
140
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
120
141
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
121
142
|
end
|
@@ -129,7 +150,12 @@ module ActiveRecord
|
|
129
150
|
end
|
130
151
|
|
131
152
|
def index_algorithms
|
132
|
-
{
|
153
|
+
{
|
154
|
+
default: "ALGORITHM = DEFAULT",
|
155
|
+
copy: "ALGORITHM = COPY",
|
156
|
+
inplace: "ALGORITHM = INPLACE",
|
157
|
+
instant: "ALGORITHM = INSTANT",
|
158
|
+
}
|
133
159
|
end
|
134
160
|
|
135
161
|
# HELPER METHODS ===========================================
|
@@ -161,27 +187,20 @@ module ActiveRecord
|
|
161
187
|
|
162
188
|
# CONNECTION MANAGEMENT ====================================
|
163
189
|
|
164
|
-
|
165
|
-
def clear_cache!
|
190
|
+
def clear_cache! # :nodoc:
|
166
191
|
reload_type_map
|
167
|
-
|
192
|
+
super
|
168
193
|
end
|
169
194
|
|
170
195
|
#--
|
171
196
|
# DATABASE STATEMENTS ======================================
|
172
197
|
#++
|
173
198
|
|
174
|
-
def explain(arel, binds = [])
|
175
|
-
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
176
|
-
start = Time.now
|
177
|
-
result = exec_query(sql, "EXPLAIN", binds)
|
178
|
-
elapsed = Time.now - start
|
179
|
-
|
180
|
-
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
181
|
-
end
|
182
|
-
|
183
199
|
# Executes the SQL statement in the context of this connection.
|
184
200
|
def execute(sql, name = nil)
|
201
|
+
materialize_transactions
|
202
|
+
mark_transaction_written_if_write(sql)
|
203
|
+
|
185
204
|
log(sql, name) do
|
186
205
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
187
206
|
@connection.query(sql)
|
@@ -197,7 +216,7 @@ module ActiveRecord
|
|
197
216
|
end
|
198
217
|
|
199
218
|
def begin_db_transaction
|
200
|
-
execute
|
219
|
+
execute("BEGIN", "TRANSACTION")
|
201
220
|
end
|
202
221
|
|
203
222
|
def begin_isolated_db_transaction(isolation)
|
@@ -206,26 +225,14 @@ module ActiveRecord
|
|
206
225
|
end
|
207
226
|
|
208
227
|
def commit_db_transaction #:nodoc:
|
209
|
-
execute
|
228
|
+
execute("COMMIT", "TRANSACTION")
|
210
229
|
end
|
211
230
|
|
212
231
|
def exec_rollback_db_transaction #:nodoc:
|
213
|
-
execute
|
232
|
+
execute("ROLLBACK", "TRANSACTION")
|
214
233
|
end
|
215
234
|
|
216
|
-
|
217
|
-
# query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
|
218
|
-
# these, we must use a subquery.
|
219
|
-
def join_to_update(update, select, key) # :nodoc:
|
220
|
-
if select.limit || select.offset || select.orders.any?
|
221
|
-
super
|
222
|
-
else
|
223
|
-
update.table select.source
|
224
|
-
update.wheres = select.constraints
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
def empty_insert_statement_value
|
235
|
+
def empty_insert_statement_value(primary_key = nil)
|
229
236
|
"VALUES ()"
|
230
237
|
end
|
231
238
|
|
@@ -241,7 +248,7 @@ module ActiveRecord
|
|
241
248
|
end
|
242
249
|
|
243
250
|
# Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>.
|
244
|
-
# Charset defaults to
|
251
|
+
# Charset defaults to utf8mb4.
|
245
252
|
#
|
246
253
|
# Example:
|
247
254
|
# create_database 'charset_test', charset: 'latin1', collation: 'latin1_bin'
|
@@ -250,8 +257,12 @@ module ActiveRecord
|
|
250
257
|
def create_database(name, options = {})
|
251
258
|
if options[:collation]
|
252
259
|
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT COLLATE #{quote_table_name(options[:collation])}"
|
260
|
+
elsif options[:charset]
|
261
|
+
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET #{quote_table_name(options[:charset])}"
|
262
|
+
elsif row_format_dynamic_by_default?
|
263
|
+
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET `utf8mb4`"
|
253
264
|
else
|
254
|
-
|
265
|
+
raise "Configure a supported :charset and ensure innodb_large_prefix is enabled to support indexes on varchar(255) string columns."
|
255
266
|
end
|
256
267
|
end
|
257
268
|
|
@@ -277,14 +288,10 @@ module ActiveRecord
|
|
277
288
|
show_variable "collation_database"
|
278
289
|
end
|
279
290
|
|
280
|
-
def truncate(table_name, name = nil)
|
281
|
-
execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
|
282
|
-
end
|
283
|
-
|
284
291
|
def table_comment(table_name) # :nodoc:
|
285
292
|
scope = quoted_scope(table_name)
|
286
293
|
|
287
|
-
query_value(
|
294
|
+
query_value(<<~SQL, "SCHEMA").presence
|
288
295
|
SELECT table_comment
|
289
296
|
FROM information_schema.tables
|
290
297
|
WHERE table_schema = #{scope[:schema]}
|
@@ -292,22 +299,8 @@ module ActiveRecord
|
|
292
299
|
SQL
|
293
300
|
end
|
294
301
|
|
295
|
-
def
|
296
|
-
|
297
|
-
table, arguments = args.shift, args
|
298
|
-
method = :"#{command}_for_alter"
|
299
|
-
|
300
|
-
if respond_to?(method, true)
|
301
|
-
send(method, table, *arguments)
|
302
|
-
else
|
303
|
-
raise "Unknown method called : #{method}(#{arguments.inspect})"
|
304
|
-
end
|
305
|
-
end.join(", ")
|
306
|
-
|
307
|
-
execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}")
|
308
|
-
end
|
309
|
-
|
310
|
-
def change_table_comment(table_name, comment) #:nodoc:
|
302
|
+
def change_table_comment(table_name, comment_or_changes) # :nodoc:
|
303
|
+
comment = extract_new_comment_value(comment_or_changes)
|
311
304
|
comment = "" if comment.nil?
|
312
305
|
execute("ALTER TABLE #{quote_table_name(table_name)} COMMENT #{quote(comment)}")
|
313
306
|
end
|
@@ -317,6 +310,8 @@ module ActiveRecord
|
|
317
310
|
# Example:
|
318
311
|
# rename_table('octopuses', 'octopi')
|
319
312
|
def rename_table(table_name, new_name)
|
313
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
314
|
+
schema_cache.clear_data_source_cache!(new_name.to_s)
|
320
315
|
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
321
316
|
rename_table_indexes(table_name, new_name)
|
322
317
|
end
|
@@ -336,7 +331,8 @@ module ActiveRecord
|
|
336
331
|
# Although this command ignores most +options+ and the block if one is given,
|
337
332
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
338
333
|
# In that case, +options+ and the block will be used by create_table.
|
339
|
-
def drop_table(table_name, options
|
334
|
+
def drop_table(table_name, **options)
|
335
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
340
336
|
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
|
341
337
|
end
|
342
338
|
|
@@ -363,12 +359,13 @@ module ActiveRecord
|
|
363
359
|
change_column table_name, column_name, nil, null: null
|
364
360
|
end
|
365
361
|
|
366
|
-
def change_column_comment(table_name, column_name,
|
362
|
+
def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
|
363
|
+
comment = extract_new_comment_value(comment_or_changes)
|
367
364
|
change_column table_name, column_name, nil, comment: comment
|
368
365
|
end
|
369
366
|
|
370
|
-
def change_column(table_name, column_name, type, options
|
371
|
-
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, options)}")
|
367
|
+
def change_column(table_name, column_name, type, **options) #:nodoc:
|
368
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
|
372
369
|
end
|
373
370
|
|
374
371
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
@@ -376,10 +373,13 @@ module ActiveRecord
|
|
376
373
|
rename_column_indexes(table_name, column_name, new_column_name)
|
377
374
|
end
|
378
375
|
|
379
|
-
def add_index(table_name, column_name, options
|
380
|
-
|
381
|
-
|
382
|
-
|
376
|
+
def add_index(table_name, column_name, **options) #:nodoc:
|
377
|
+
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
378
|
+
|
379
|
+
return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
|
380
|
+
|
381
|
+
create_index = CreateIndexDefinition.new(index, algorithm)
|
382
|
+
execute schema_creation.accept(create_index)
|
383
383
|
end
|
384
384
|
|
385
385
|
def add_sql_comment!(sql, comment) # :nodoc:
|
@@ -392,7 +392,7 @@ module ActiveRecord
|
|
392
392
|
|
393
393
|
scope = quoted_scope(table_name)
|
394
394
|
|
395
|
-
fk_info = exec_query(
|
395
|
+
fk_info = exec_query(<<~SQL, "SCHEMA")
|
396
396
|
SELECT fk.referenced_table_name AS 'to_table',
|
397
397
|
fk.referenced_column_name AS 'primary_key',
|
398
398
|
fk.column_name AS 'column',
|
@@ -423,51 +423,63 @@ module ActiveRecord
|
|
423
423
|
end
|
424
424
|
end
|
425
425
|
|
426
|
-
def
|
427
|
-
|
426
|
+
def check_constraints(table_name)
|
427
|
+
if supports_check_constraints?
|
428
|
+
scope = quoted_scope(table_name)
|
429
|
+
|
430
|
+
chk_info = exec_query(<<~SQL, "SCHEMA")
|
431
|
+
SELECT cc.constraint_name AS 'name',
|
432
|
+
cc.check_clause AS 'expression'
|
433
|
+
FROM information_schema.check_constraints cc
|
434
|
+
JOIN information_schema.table_constraints tc
|
435
|
+
USING (constraint_schema, constraint_name)
|
436
|
+
WHERE tc.table_schema = #{scope[:schema]}
|
437
|
+
AND tc.table_name = #{scope[:name]}
|
438
|
+
AND cc.constraint_schema = #{scope[:schema]}
|
439
|
+
SQL
|
440
|
+
|
441
|
+
chk_info.map do |row|
|
442
|
+
options = {
|
443
|
+
name: row["name"]
|
444
|
+
}
|
445
|
+
expression = row["expression"]
|
446
|
+
expression = expression[1..-2] unless mariadb? # remove parentheses added by mysql
|
447
|
+
CheckConstraintDefinition.new(table_name, expression, options)
|
448
|
+
end
|
449
|
+
else
|
450
|
+
raise NotImplementedError
|
451
|
+
end
|
452
|
+
end
|
428
453
|
|
454
|
+
def table_options(table_name) # :nodoc:
|
429
455
|
create_table_info = create_table_info(table_name)
|
430
456
|
|
431
457
|
# strip create_definitions and partition_options
|
432
|
-
|
458
|
+
# Be aware that `create_table_info` might not include any table options due to `NO_TABLE_OPTIONS` sql mode.
|
459
|
+
raw_table_options = create_table_info.sub(/\A.*\n\) ?/m, "").sub(/\n\/\*!.*\*\/\n\z/m, "").strip
|
460
|
+
|
461
|
+
return if raw_table_options.empty?
|
462
|
+
|
463
|
+
table_options = {}
|
464
|
+
|
465
|
+
if / DEFAULT CHARSET=(?<charset>\w+)(?: COLLATE=(?<collation>\w+))?/ =~ raw_table_options
|
466
|
+
raw_table_options = $` + $' # before part + after part
|
467
|
+
table_options[:charset] = charset
|
468
|
+
table_options[:collation] = collation if collation
|
469
|
+
end
|
433
470
|
|
434
471
|
# strip AUTO_INCREMENT
|
435
472
|
raw_table_options.sub!(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1')
|
436
473
|
|
437
|
-
table_options[:options] = raw_table_options
|
438
|
-
|
439
474
|
# strip COMMENT
|
440
475
|
if raw_table_options.sub!(/ COMMENT='.+'/, "")
|
441
476
|
table_options[:comment] = table_comment(table_name)
|
442
477
|
end
|
443
478
|
|
479
|
+
table_options[:options] = raw_table_options unless raw_table_options == "ENGINE=InnoDB"
|
444
480
|
table_options
|
445
481
|
end
|
446
482
|
|
447
|
-
# Maps logical Rails types to MySQL-specific data types.
|
448
|
-
def type_to_sql(type, limit: nil, precision: nil, scale: nil, unsigned: nil, **) # :nodoc:
|
449
|
-
sql = \
|
450
|
-
case type.to_s
|
451
|
-
when "integer"
|
452
|
-
integer_to_sql(limit)
|
453
|
-
when "text"
|
454
|
-
text_to_sql(limit)
|
455
|
-
when "blob"
|
456
|
-
binary_to_sql(limit)
|
457
|
-
when "binary"
|
458
|
-
if (0..0xfff) === limit
|
459
|
-
"varbinary(#{limit})"
|
460
|
-
else
|
461
|
-
binary_to_sql(limit)
|
462
|
-
end
|
463
|
-
else
|
464
|
-
super
|
465
|
-
end
|
466
|
-
|
467
|
-
sql = "#{sql} unsigned" if unsigned && type != :primary_key
|
468
|
-
sql
|
469
|
-
end
|
470
|
-
|
471
483
|
# SHOW VARIABLES LIKE 'name'
|
472
484
|
def show_variable(name)
|
473
485
|
query_value("SELECT @@#{name}", "SCHEMA")
|
@@ -480,19 +492,21 @@ module ActiveRecord
|
|
480
492
|
|
481
493
|
scope = quoted_scope(table_name)
|
482
494
|
|
483
|
-
query_values(
|
495
|
+
query_values(<<~SQL, "SCHEMA")
|
484
496
|
SELECT column_name
|
485
|
-
FROM information_schema.
|
486
|
-
WHERE
|
497
|
+
FROM information_schema.statistics
|
498
|
+
WHERE index_name = 'PRIMARY'
|
487
499
|
AND table_schema = #{scope[:schema]}
|
488
500
|
AND table_name = #{scope[:name]}
|
489
|
-
ORDER BY
|
501
|
+
ORDER BY seq_in_index
|
490
502
|
SQL
|
491
503
|
end
|
492
504
|
|
493
|
-
def case_sensitive_comparison(
|
505
|
+
def case_sensitive_comparison(attribute, value) # :nodoc:
|
506
|
+
column = column_for_attribute(attribute)
|
507
|
+
|
494
508
|
if column.collation && !column.case_sensitive?
|
495
|
-
|
509
|
+
attribute.eq(Arel::Nodes::Bin.new(value))
|
496
510
|
else
|
497
511
|
super
|
498
512
|
end
|
@@ -506,14 +520,14 @@ module ActiveRecord
|
|
506
520
|
# In MySQL 5.7.5 and up, ONLY_FULL_GROUP_BY affects handling of queries that use
|
507
521
|
# DISTINCT and ORDER BY. It requires the ORDER BY columns in the select list for
|
508
522
|
# distinct queries, and requires that the ORDER BY include the distinct column.
|
509
|
-
# See https://dev.mysql.com/doc/refman/
|
523
|
+
# See https://dev.mysql.com/doc/refman/en/group-by-handling.html
|
510
524
|
def columns_for_distinct(columns, orders) # :nodoc:
|
511
|
-
order_columns = orders.
|
525
|
+
order_columns = orders.compact_blank.map { |s|
|
512
526
|
# Convert Arel node to string
|
513
|
-
s = s
|
527
|
+
s = visitor.compile(s) unless s.is_a?(String)
|
514
528
|
# Remove any ASC/DESC modifiers
|
515
529
|
s.gsub(/\s+(?:ASC|DESC)\b/i, "")
|
516
|
-
}.
|
530
|
+
}.compact_blank.map.with_index { |column, i| "#{column} AS alias_#{i}" }
|
517
531
|
|
518
532
|
(order_columns << super).join(", ")
|
519
533
|
end
|
@@ -526,44 +540,35 @@ module ActiveRecord
|
|
526
540
|
index.using == :btree || super
|
527
541
|
end
|
528
542
|
|
529
|
-
def
|
530
|
-
|
531
|
-
super { discard_remaining_results }
|
532
|
-
end
|
533
|
-
end
|
543
|
+
def build_insert_sql(insert) # :nodoc:
|
544
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
534
545
|
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
else
|
543
|
-
previous_packet << sql
|
544
|
-
end
|
545
|
-
end
|
546
|
+
if insert.skip_duplicates?
|
547
|
+
no_op_column = quote_column_name(insert.keys.first)
|
548
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
549
|
+
elsif insert.update_duplicates?
|
550
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
551
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
|
552
|
+
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
546
553
|
end
|
547
554
|
|
548
|
-
|
549
|
-
|
550
|
-
raise ActiveRecordError, "Fixtures set is too large #{current_packet.bytesize}. Consider increasing the max_allowed_packet variable."
|
551
|
-
elsif previous_packet.nil?
|
552
|
-
false
|
553
|
-
else
|
554
|
-
(current_packet.bytesize + previous_packet.bytesize) > max_allowed_packet
|
555
|
-
end
|
556
|
-
end
|
555
|
+
sql
|
556
|
+
end
|
557
557
|
|
558
|
-
|
559
|
-
|
560
|
-
|
558
|
+
def check_version # :nodoc:
|
559
|
+
if database_version < "5.5.8"
|
560
|
+
raise "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
|
561
561
|
end
|
562
|
+
end
|
562
563
|
|
564
|
+
private
|
563
565
|
def initialize_type_map(m = type_map)
|
564
566
|
super
|
565
567
|
|
566
|
-
|
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
|
567
572
|
|
568
573
|
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
569
574
|
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
@@ -583,28 +588,19 @@ module ActiveRecord
|
|
583
588
|
register_integer_type m, %r(^tinyint)i, limit: 1
|
584
589
|
|
585
590
|
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
|
586
|
-
m.alias_type %r(year)i,
|
587
|
-
m.alias_type %r(bit)i,
|
588
|
-
|
589
|
-
m.register_type(%r(enum)i) do |sql_type|
|
590
|
-
limit = sql_type[/^enum\((.+)\)/i, 1]
|
591
|
-
.split(",").map { |enum| enum.strip.length - 2 }.max
|
592
|
-
MysqlString.new(limit: limit)
|
593
|
-
end
|
591
|
+
m.alias_type %r(year)i, "integer"
|
592
|
+
m.alias_type %r(bit)i, "binary"
|
594
593
|
|
595
|
-
m.register_type
|
596
|
-
|
597
|
-
.split(",").map { |set| set.strip.length - 1 }.sum - 1
|
598
|
-
MysqlString.new(limit: limit)
|
599
|
-
end
|
594
|
+
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
|
595
|
+
m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
|
600
596
|
end
|
601
597
|
|
602
|
-
def register_integer_type(mapping, key, options)
|
598
|
+
def register_integer_type(mapping, key, **options)
|
603
599
|
mapping.register_type(key) do |sql_type|
|
604
600
|
if /\bunsigned\b/.match?(sql_type)
|
605
|
-
Type::UnsignedInteger.new(options)
|
601
|
+
Type::UnsignedInteger.new(**options)
|
606
602
|
else
|
607
|
-
Type::Integer.new(options)
|
603
|
+
Type::Integer.new(**options)
|
608
604
|
end
|
609
605
|
end
|
610
606
|
end
|
@@ -617,10 +613,15 @@ module ActiveRecord
|
|
617
613
|
end
|
618
614
|
end
|
619
615
|
|
620
|
-
# See https://dev.mysql.com/doc/
|
616
|
+
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
|
617
|
+
ER_DB_CREATE_EXISTS = 1007
|
618
|
+
ER_FILSORT_ABORT = 1028
|
621
619
|
ER_DUP_ENTRY = 1062
|
622
620
|
ER_NOT_NULL_VIOLATION = 1048
|
621
|
+
ER_NO_REFERENCED_ROW = 1216
|
622
|
+
ER_ROW_IS_REFERENCED = 1217
|
623
623
|
ER_DO_NOT_HAVE_DEFAULT = 1364
|
624
|
+
ER_ROW_IS_REFERENCED_2 = 1451
|
624
625
|
ER_NO_REFERENCED_ROW_2 = 1452
|
625
626
|
ER_DATA_TOO_LONG = 1406
|
626
627
|
ER_OUT_OF_RANGE = 1264
|
@@ -630,41 +631,50 @@ module ActiveRecord
|
|
630
631
|
ER_LOCK_WAIT_TIMEOUT = 1205
|
631
632
|
ER_QUERY_INTERRUPTED = 1317
|
632
633
|
ER_QUERY_TIMEOUT = 3024
|
634
|
+
ER_FK_INCOMPATIBLE_COLUMNS = 3780
|
633
635
|
|
634
|
-
def translate_exception(exception, message)
|
636
|
+
def translate_exception(exception, message:, sql:, binds:)
|
635
637
|
case error_number(exception)
|
638
|
+
when nil
|
639
|
+
if exception.message.match?(/MySQL client is not connected/i)
|
640
|
+
ConnectionNotEstablished.new(exception)
|
641
|
+
else
|
642
|
+
super
|
643
|
+
end
|
644
|
+
when ER_DB_CREATE_EXISTS
|
645
|
+
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
|
636
646
|
when ER_DUP_ENTRY
|
637
|
-
RecordNotUnique.new(message)
|
638
|
-
when ER_NO_REFERENCED_ROW_2
|
639
|
-
InvalidForeignKey.new(message)
|
640
|
-
when ER_CANNOT_ADD_FOREIGN
|
641
|
-
mismatched_foreign_key(message)
|
647
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
648
|
+
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)
|
650
|
+
when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
|
651
|
+
mismatched_foreign_key(message, sql: sql, binds: binds)
|
642
652
|
when ER_CANNOT_CREATE_TABLE
|
643
653
|
if message.include?("errno: 150")
|
644
|
-
mismatched_foreign_key(message)
|
654
|
+
mismatched_foreign_key(message, sql: sql, binds: binds)
|
645
655
|
else
|
646
656
|
super
|
647
657
|
end
|
648
658
|
when ER_DATA_TOO_LONG
|
649
|
-
ValueTooLong.new(message)
|
659
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
650
660
|
when ER_OUT_OF_RANGE
|
651
|
-
RangeError.new(message)
|
661
|
+
RangeError.new(message, sql: sql, binds: binds)
|
652
662
|
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
653
|
-
NotNullViolation.new(message)
|
663
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
654
664
|
when ER_LOCK_DEADLOCK
|
655
|
-
Deadlocked.new(message)
|
665
|
+
Deadlocked.new(message, sql: sql, binds: binds)
|
656
666
|
when ER_LOCK_WAIT_TIMEOUT
|
657
|
-
LockWaitTimeout.new(message)
|
658
|
-
when ER_QUERY_TIMEOUT
|
659
|
-
StatementTimeout.new(message)
|
667
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
668
|
+
when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
|
669
|
+
StatementTimeout.new(message, sql: sql, binds: binds)
|
660
670
|
when ER_QUERY_INTERRUPTED
|
661
|
-
QueryCanceled.new(message)
|
671
|
+
QueryCanceled.new(message, sql: sql, binds: binds)
|
662
672
|
else
|
663
673
|
super
|
664
674
|
end
|
665
675
|
end
|
666
676
|
|
667
|
-
def change_column_for_alter(table_name, column_name, type, options
|
677
|
+
def change_column_for_alter(table_name, column_name, type, **options)
|
668
678
|
column = column_for(table_name, column_name)
|
669
679
|
type ||= column.sql_type
|
670
680
|
|
@@ -681,59 +691,53 @@ module ActiveRecord
|
|
681
691
|
end
|
682
692
|
|
683
693
|
td = create_table_definition(table_name)
|
684
|
-
cd = td.new_column_definition(column.name, type, options)
|
694
|
+
cd = td.new_column_definition(column.name, type, **options)
|
685
695
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
686
696
|
end
|
687
697
|
|
688
698
|
def rename_column_for_alter(table_name, column_name, new_column_name)
|
699
|
+
return rename_column_sql(table_name, column_name, new_column_name) if supports_rename_column?
|
700
|
+
|
689
701
|
column = column_for(table_name, column_name)
|
690
702
|
options = {
|
691
703
|
default: column.default,
|
692
704
|
null: column.null,
|
693
|
-
auto_increment: column.auto_increment
|
705
|
+
auto_increment: column.auto_increment?,
|
706
|
+
comment: column.comment
|
694
707
|
}
|
695
708
|
|
696
709
|
current_type = exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
|
697
710
|
td = create_table_definition(table_name)
|
698
|
-
cd = td.new_column_definition(new_column_name, current_type, options)
|
711
|
+
cd = td.new_column_definition(new_column_name, current_type, **options)
|
699
712
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
700
713
|
end
|
701
714
|
|
702
|
-
def add_index_for_alter(table_name, column_name, options
|
703
|
-
|
704
|
-
|
705
|
-
"ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
|
706
|
-
end
|
707
|
-
|
708
|
-
def remove_index_for_alter(table_name, options = {})
|
709
|
-
index_name = index_name_for_remove(table_name, options)
|
710
|
-
"DROP INDEX #{quote_column_name(index_name)}"
|
711
|
-
end
|
715
|
+
def add_index_for_alter(table_name, column_name, **options)
|
716
|
+
index, algorithm, _ = add_index_options(table_name, column_name, **options)
|
717
|
+
algorithm = ", #{algorithm}" if algorithm
|
712
718
|
|
713
|
-
|
714
|
-
[add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
|
719
|
+
"ADD #{schema_creation.accept(index)}#{algorithm}"
|
715
720
|
end
|
716
721
|
|
717
|
-
def
|
718
|
-
|
722
|
+
def remove_index_for_alter(table_name, column_name = nil, **options)
|
723
|
+
index_name = index_name_for_remove(table_name, column_name, options)
|
724
|
+
"DROP INDEX #{quote_column_name(index_name)}"
|
719
725
|
end
|
720
726
|
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
# Materialize subquery by adding distinct
|
728
|
-
# to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
|
729
|
-
subselect.distinct unless select.limit || select.offset || select.orders.any?
|
730
|
-
|
731
|
-
key_name = quote_column_name(key.name)
|
732
|
-
Arel::SelectManager.new(subselect.as("__active_record_temp")).project(Arel.sql(key_name))
|
727
|
+
def supports_rename_index?
|
728
|
+
if mariadb?
|
729
|
+
database_version >= "10.5.2"
|
730
|
+
else
|
731
|
+
database_version >= "5.7.6"
|
732
|
+
end
|
733
733
|
end
|
734
734
|
|
735
|
-
def
|
736
|
-
mariadb?
|
735
|
+
def supports_rename_column?
|
736
|
+
if mariadb?
|
737
|
+
database_version >= "10.5.2"
|
738
|
+
else
|
739
|
+
database_version >= "8.0.3"
|
740
|
+
end
|
737
741
|
end
|
738
742
|
|
739
743
|
def configure_connection
|
@@ -750,7 +754,7 @@ module ActiveRecord
|
|
750
754
|
defaults = [":default", :default].to_set
|
751
755
|
|
752
756
|
# Make MySQL reject illegal values rather than truncating or blanking them, see
|
753
|
-
# https://dev.mysql.com/doc/refman/
|
757
|
+
# https://dev.mysql.com/doc/refman/en/sql-mode.html#sqlmode_strict_all_tables
|
754
758
|
# If the user has provided another value for sql_mode, don't replace it.
|
755
759
|
if sql_mode = variables.delete("sql_mode")
|
756
760
|
sql_mode = quote(sql_mode)
|
@@ -767,10 +771,10 @@ module ActiveRecord
|
|
767
771
|
sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
|
768
772
|
|
769
773
|
# NAMES does not have an equals sign, see
|
770
|
-
# https://dev.mysql.com/doc/refman/
|
774
|
+
# https://dev.mysql.com/doc/refman/en/set-names.html
|
771
775
|
# (trailing comma because variable_assignments will always have content)
|
772
776
|
if @config[:encoding]
|
773
|
-
encoding = "NAMES #{@config[:encoding]}"
|
777
|
+
encoding = +"NAMES #{@config[:encoding]}"
|
774
778
|
encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
|
775
779
|
encoding << ", "
|
776
780
|
end
|
@@ -786,7 +790,7 @@ module ActiveRecord
|
|
786
790
|
end.compact.join(", ")
|
787
791
|
|
788
792
|
# ...and send them all in one query
|
789
|
-
execute
|
793
|
+
execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
790
794
|
end
|
791
795
|
|
792
796
|
def column_definitions(table_name) # :nodoc:
|
@@ -803,15 +807,21 @@ module ActiveRecord
|
|
803
807
|
Arel::Visitors::MySQL.new(self)
|
804
808
|
end
|
805
809
|
|
806
|
-
def
|
810
|
+
def build_statement_pool
|
811
|
+
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
812
|
+
end
|
813
|
+
|
814
|
+
def mismatched_foreign_key(message, sql:, binds:)
|
807
815
|
match = %r/
|
808
816
|
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
809
817
|
FOREIGN\s+KEY\s*\(`?(?<foreign_key>\w+)`?\)\s*
|
810
818
|
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
811
|
-
/xmi.match(
|
819
|
+
/xmi.match(sql)
|
812
820
|
|
813
821
|
options = {
|
814
822
|
message: message,
|
823
|
+
sql: sql,
|
824
|
+
binds: binds,
|
815
825
|
}
|
816
826
|
|
817
827
|
if match
|
@@ -822,65 +832,23 @@ module ActiveRecord
|
|
822
832
|
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
823
833
|
end
|
824
834
|
|
825
|
-
MismatchedForeignKey.new(options)
|
835
|
+
MismatchedForeignKey.new(**options)
|
826
836
|
end
|
827
837
|
|
828
|
-
def
|
829
|
-
|
830
|
-
when 1; "tinyint"
|
831
|
-
when 2; "smallint"
|
832
|
-
when 3; "mediumint"
|
833
|
-
when nil, 4; "int"
|
834
|
-
when 5..8; "bigint"
|
835
|
-
else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a decimal with scale 0 instead.")
|
836
|
-
end
|
838
|
+
def version_string(full_version_string)
|
839
|
+
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
837
840
|
end
|
838
841
|
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
when nil, 0x100..0xffff; "text"
|
843
|
-
when 0x10000..0xffffff; "mediumtext"
|
844
|
-
when 0x1000000..0xffffffff; "longtext"
|
845
|
-
else raise(ActiveRecordError, "No text type has byte length #{limit}")
|
846
|
-
end
|
847
|
-
end
|
848
|
-
|
849
|
-
def binary_to_sql(limit) # :nodoc:
|
850
|
-
case limit
|
851
|
-
when 0..0xff; "tinyblob"
|
852
|
-
when nil, 0x100..0xffff; "blob"
|
853
|
-
when 0x10000..0xffffff; "mediumblob"
|
854
|
-
when 0x1000000..0xffffffff; "longblob"
|
855
|
-
else raise(ActiveRecordError, "No binary type has byte length #{limit}")
|
856
|
-
end
|
857
|
-
end
|
842
|
+
# Alias MysqlString to work Mashal.load(File.read("legacy_record.dump")).
|
843
|
+
# TODO: Remove the constant alias once Rails 6.1 has released.
|
844
|
+
MysqlString = Type::String # :nodoc:
|
858
845
|
|
859
|
-
|
860
|
-
|
846
|
+
ActiveRecord::Type.register(:immutable_string, adapter: :mysql2) do |_, **args|
|
847
|
+
Type::ImmutableString.new(true: "1", false: "0", **args)
|
861
848
|
end
|
862
|
-
|
863
|
-
|
864
|
-
def serialize(value)
|
865
|
-
case value
|
866
|
-
when true then "1"
|
867
|
-
when false then "0"
|
868
|
-
else super
|
869
|
-
end
|
870
|
-
end
|
871
|
-
|
872
|
-
private
|
873
|
-
|
874
|
-
def cast_value(value)
|
875
|
-
case value
|
876
|
-
when true then "1"
|
877
|
-
when false then "0"
|
878
|
-
else super
|
879
|
-
end
|
880
|
-
end
|
849
|
+
ActiveRecord::Type.register(:string, adapter: :mysql2) do |_, **args|
|
850
|
+
Type::String.new(true: "1", false: "0", **args)
|
881
851
|
end
|
882
|
-
|
883
|
-
ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2)
|
884
852
|
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
|
885
853
|
end
|
886
854
|
end
|