activerecord 5.2.4.4 → 6.0.0
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 +611 -590
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +9 -2
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations.rb +19 -14
- data/lib/active_record/associations/association.rb +52 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +6 -21
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -10
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +24 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +40 -32
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -22
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -53
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +17 -24
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +5 -9
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +5 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +94 -16
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +95 -123
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +132 -53
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +180 -47
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +128 -194
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +73 -13
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.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 +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +160 -74
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +125 -141
- data/lib/active_record/connection_handling.rb +149 -27
- data/lib/active_record/core.rb +100 -60
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +37 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +145 -472
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +10 -2
- data/lib/active_record/locking/optimistic.rb +5 -6
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +100 -81
- data/lib/active_record/migration/command_recorder.rb +50 -6
- data/lib/active_record/migration/compatibility.rb +76 -49
- data/lib/active_record/model_schema.rb +30 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +228 -24
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +32 -20
- data/lib/active_record/railtie.rb +80 -43
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +196 -46
- data/lib/active_record/reflection.rb +32 -30
- data/lib/active_record/relation.rb +310 -80
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +53 -47
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +13 -26
- data/lib/active_record/relation/merger.rb +11 -20
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +189 -63
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +14 -10
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +5 -1
- data/lib/active_record/scoping.rb +8 -8
- data/lib/active_record/scoping/default.rb +4 -5
- data/lib/active_record/scoping/named.rb +19 -15
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/table_metadata.rb +10 -17
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +57 -66
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/arel.rb +51 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -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.rb +68 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -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 +18 -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 +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -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 +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -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 +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -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/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +108 -26
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -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,44 @@ 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
|
-
|
50
|
-
|
47
|
+
private
|
48
|
+
|
49
|
+
def dealloc(stmt)
|
50
|
+
stmt.close
|
51
|
+
end
|
51
52
|
end
|
52
53
|
|
53
54
|
def initialize(connection, logger, connection_options, config)
|
54
55
|
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
56
|
end
|
62
57
|
|
63
|
-
def
|
64
|
-
|
58
|
+
def get_database_version #:nodoc:
|
59
|
+
full_version_string = get_full_version
|
60
|
+
version_string = version_string(full_version_string)
|
61
|
+
Version.new(version_string, full_version_string)
|
65
62
|
end
|
66
63
|
|
67
64
|
def mariadb? # :nodoc:
|
68
65
|
/mariadb/i.match?(full_version)
|
69
66
|
end
|
70
67
|
|
71
|
-
def supports_bulk_alter?
|
68
|
+
def supports_bulk_alter?
|
72
69
|
true
|
73
70
|
end
|
74
71
|
|
75
72
|
def supports_index_sort_order?
|
76
|
-
!mariadb? &&
|
73
|
+
!mariadb? && database_version >= "8.0.1"
|
74
|
+
end
|
75
|
+
|
76
|
+
def supports_expression_index?
|
77
|
+
!mariadb? && database_version >= "8.0.13"
|
77
78
|
end
|
78
79
|
|
79
80
|
def supports_transaction_isolation?
|
@@ -97,25 +98,30 @@ module ActiveRecord
|
|
97
98
|
end
|
98
99
|
|
99
100
|
def supports_datetime_with_precision?
|
100
|
-
|
101
|
-
version >= "5.3.0"
|
102
|
-
else
|
103
|
-
version >= "5.6.4"
|
104
|
-
end
|
101
|
+
mariadb? || database_version >= "5.6.4"
|
105
102
|
end
|
106
103
|
|
107
104
|
def supports_virtual_columns?
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
105
|
+
mariadb? || database_version >= "5.7.5"
|
106
|
+
end
|
107
|
+
|
108
|
+
# See https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html for more details.
|
109
|
+
def supports_optimizer_hints?
|
110
|
+
!mariadb? && database_version >= "5.7.7"
|
113
111
|
end
|
114
112
|
|
115
113
|
def supports_advisory_locks?
|
116
114
|
true
|
117
115
|
end
|
118
116
|
|
117
|
+
def supports_insert_on_duplicate_skip?
|
118
|
+
true
|
119
|
+
end
|
120
|
+
|
121
|
+
def supports_insert_on_duplicate_update?
|
122
|
+
true
|
123
|
+
end
|
124
|
+
|
119
125
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
120
126
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
121
127
|
end
|
@@ -129,7 +135,7 @@ module ActiveRecord
|
|
129
135
|
end
|
130
136
|
|
131
137
|
def index_algorithms
|
132
|
-
{ default: "ALGORITHM = DEFAULT"
|
138
|
+
{ default: +"ALGORITHM = DEFAULT", copy: +"ALGORITHM = COPY", inplace: +"ALGORITHM = INPLACE" }
|
133
139
|
end
|
134
140
|
|
135
141
|
# HELPER METHODS ===========================================
|
@@ -161,10 +167,9 @@ module ActiveRecord
|
|
161
167
|
|
162
168
|
# CONNECTION MANAGEMENT ====================================
|
163
169
|
|
164
|
-
|
165
|
-
def clear_cache!
|
170
|
+
def clear_cache! # :nodoc:
|
166
171
|
reload_type_map
|
167
|
-
|
172
|
+
super
|
168
173
|
end
|
169
174
|
|
170
175
|
#--
|
@@ -173,15 +178,17 @@ module ActiveRecord
|
|
173
178
|
|
174
179
|
def explain(arel, binds = [])
|
175
180
|
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
176
|
-
start =
|
181
|
+
start = Concurrent.monotonic_time
|
177
182
|
result = exec_query(sql, "EXPLAIN", binds)
|
178
|
-
elapsed =
|
183
|
+
elapsed = Concurrent.monotonic_time - start
|
179
184
|
|
180
185
|
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
181
186
|
end
|
182
187
|
|
183
188
|
# Executes the SQL statement in the context of this connection.
|
184
189
|
def execute(sql, name = nil)
|
190
|
+
materialize_transactions
|
191
|
+
|
185
192
|
log(sql, name) do
|
186
193
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
187
194
|
@connection.query(sql)
|
@@ -213,19 +220,7 @@ module ActiveRecord
|
|
213
220
|
execute "ROLLBACK"
|
214
221
|
end
|
215
222
|
|
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
|
223
|
+
def empty_insert_statement_value(primary_key = nil)
|
229
224
|
"VALUES ()"
|
230
225
|
end
|
231
226
|
|
@@ -241,7 +236,7 @@ module ActiveRecord
|
|
241
236
|
end
|
242
237
|
|
243
238
|
# Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>.
|
244
|
-
# Charset defaults to
|
239
|
+
# Charset defaults to utf8mb4.
|
245
240
|
#
|
246
241
|
# Example:
|
247
242
|
# create_database 'charset_test', charset: 'latin1', collation: 'latin1_bin'
|
@@ -250,8 +245,12 @@ module ActiveRecord
|
|
250
245
|
def create_database(name, options = {})
|
251
246
|
if options[:collation]
|
252
247
|
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT COLLATE #{quote_table_name(options[:collation])}"
|
248
|
+
elsif options[:charset]
|
249
|
+
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET #{quote_table_name(options[:charset])}"
|
250
|
+
elsif row_format_dynamic_by_default?
|
251
|
+
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET `utf8mb4`"
|
253
252
|
else
|
254
|
-
|
253
|
+
raise "Configure a supported :charset and ensure innodb_large_prefix is enabled to support indexes on varchar(255) string columns."
|
255
254
|
end
|
256
255
|
end
|
257
256
|
|
@@ -277,14 +276,10 @@ module ActiveRecord
|
|
277
276
|
show_variable "collation_database"
|
278
277
|
end
|
279
278
|
|
280
|
-
def truncate(table_name, name = nil)
|
281
|
-
execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
|
282
|
-
end
|
283
|
-
|
284
279
|
def table_comment(table_name) # :nodoc:
|
285
280
|
scope = quoted_scope(table_name)
|
286
281
|
|
287
|
-
query_value(
|
282
|
+
query_value(<<~SQL, "SCHEMA").presence
|
288
283
|
SELECT table_comment
|
289
284
|
FROM information_schema.tables
|
290
285
|
WHERE table_schema = #{scope[:schema]}
|
@@ -292,22 +287,8 @@ module ActiveRecord
|
|
292
287
|
SQL
|
293
288
|
end
|
294
289
|
|
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:
|
290
|
+
def change_table_comment(table_name, comment_or_changes) # :nodoc:
|
291
|
+
comment = extract_new_comment_value(comment_or_changes)
|
311
292
|
comment = "" if comment.nil?
|
312
293
|
execute("ALTER TABLE #{quote_table_name(table_name)} COMMENT #{quote(comment)}")
|
313
294
|
end
|
@@ -363,7 +344,8 @@ module ActiveRecord
|
|
363
344
|
change_column table_name, column_name, nil, null: null
|
364
345
|
end
|
365
346
|
|
366
|
-
def change_column_comment(table_name, column_name,
|
347
|
+
def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
|
348
|
+
comment = extract_new_comment_value(comment_or_changes)
|
367
349
|
change_column table_name, column_name, nil, comment: comment
|
368
350
|
end
|
369
351
|
|
@@ -378,7 +360,7 @@ module ActiveRecord
|
|
378
360
|
|
379
361
|
def add_index(table_name, column_name, options = {}) #:nodoc:
|
380
362
|
index_name, index_type, index_columns, _, index_algorithm, index_using, comment = add_index_options(table_name, column_name, options)
|
381
|
-
sql = "CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns}) #{index_algorithm}"
|
363
|
+
sql = +"CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns}) #{index_algorithm}"
|
382
364
|
execute add_sql_comment!(sql, comment)
|
383
365
|
end
|
384
366
|
|
@@ -392,7 +374,7 @@ module ActiveRecord
|
|
392
374
|
|
393
375
|
scope = quoted_scope(table_name)
|
394
376
|
|
395
|
-
fk_info = exec_query(
|
377
|
+
fk_info = exec_query(<<~SQL, "SCHEMA")
|
396
378
|
SELECT fk.referenced_table_name AS 'to_table',
|
397
379
|
fk.referenced_column_name AS 'primary_key',
|
398
380
|
fk.column_name AS 'column',
|
@@ -444,30 +426,6 @@ module ActiveRecord
|
|
444
426
|
table_options
|
445
427
|
end
|
446
428
|
|
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
429
|
# SHOW VARIABLES LIKE 'name'
|
472
430
|
def show_variable(name)
|
473
431
|
query_value("SELECT @@#{name}", "SCHEMA")
|
@@ -480,7 +438,7 @@ module ActiveRecord
|
|
480
438
|
|
481
439
|
scope = quoted_scope(table_name)
|
482
440
|
|
483
|
-
query_values(
|
441
|
+
query_values(<<~SQL, "SCHEMA")
|
484
442
|
SELECT column_name
|
485
443
|
FROM information_schema.key_column_usage
|
486
444
|
WHERE constraint_name = 'PRIMARY'
|
@@ -490,9 +448,26 @@ module ActiveRecord
|
|
490
448
|
SQL
|
491
449
|
end
|
492
450
|
|
493
|
-
def
|
451
|
+
def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
|
452
|
+
column = column_for_attribute(attribute)
|
453
|
+
|
454
|
+
if column.collation && !column.case_sensitive? && !value.nil?
|
455
|
+
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
456
|
+
Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1.
|
457
|
+
To continue case sensitive comparison on the :#{attribute.name} attribute in #{klass} model,
|
458
|
+
pass `case_sensitive: true` option explicitly to the uniqueness validator.
|
459
|
+
MSG
|
460
|
+
attribute.eq(Arel::Nodes::Bin.new(value))
|
461
|
+
else
|
462
|
+
super
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
def case_sensitive_comparison(attribute, value) # :nodoc:
|
467
|
+
column = column_for_attribute(attribute)
|
468
|
+
|
494
469
|
if column.collation && !column.case_sensitive?
|
495
|
-
|
470
|
+
attribute.eq(Arel::Nodes::Bin.new(value))
|
496
471
|
else
|
497
472
|
super
|
498
473
|
end
|
@@ -526,39 +501,27 @@ module ActiveRecord
|
|
526
501
|
index.using == :btree || super
|
527
502
|
end
|
528
503
|
|
529
|
-
def
|
530
|
-
|
531
|
-
super { discard_remaining_results }
|
532
|
-
end
|
533
|
-
end
|
504
|
+
def build_insert_sql(insert) # :nodoc:
|
505
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
534
506
|
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
total_sql_chunks << sql
|
542
|
-
else
|
543
|
-
previous_packet << sql
|
544
|
-
end
|
545
|
-
end
|
507
|
+
if insert.skip_duplicates?
|
508
|
+
no_op_column = quote_column_name(insert.keys.first)
|
509
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
510
|
+
elsif insert.update_duplicates?
|
511
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
512
|
+
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
546
513
|
end
|
547
514
|
|
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
|
515
|
+
sql
|
516
|
+
end
|
557
517
|
|
558
|
-
|
559
|
-
|
560
|
-
|
518
|
+
def check_version # :nodoc:
|
519
|
+
if database_version < "5.5.8"
|
520
|
+
raise "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
|
561
521
|
end
|
522
|
+
end
|
523
|
+
|
524
|
+
private
|
562
525
|
|
563
526
|
def initialize_type_map(m = type_map)
|
564
527
|
super
|
@@ -587,13 +550,13 @@ module ActiveRecord
|
|
587
550
|
m.alias_type %r(bit)i, "binary"
|
588
551
|
|
589
552
|
m.register_type(%r(enum)i) do |sql_type|
|
590
|
-
limit = sql_type[/^enum\((.+)\)/i, 1]
|
553
|
+
limit = sql_type[/^enum\s*\((.+)\)/i, 1]
|
591
554
|
.split(",").map { |enum| enum.strip.length - 2 }.max
|
592
555
|
MysqlString.new(limit: limit)
|
593
556
|
end
|
594
557
|
|
595
558
|
m.register_type(%r(^set)i) do |sql_type|
|
596
|
-
limit = sql_type[/^set\((.+)\)/i, 1]
|
559
|
+
limit = sql_type[/^set\s*\((.+)\)/i, 1]
|
597
560
|
.split(",").map { |set| set.strip.length - 1 }.sum - 1
|
598
561
|
MysqlString.new(limit: limit)
|
599
562
|
end
|
@@ -620,7 +583,10 @@ module ActiveRecord
|
|
620
583
|
# See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
|
621
584
|
ER_DUP_ENTRY = 1062
|
622
585
|
ER_NOT_NULL_VIOLATION = 1048
|
586
|
+
ER_NO_REFERENCED_ROW = 1216
|
587
|
+
ER_ROW_IS_REFERENCED = 1217
|
623
588
|
ER_DO_NOT_HAVE_DEFAULT = 1364
|
589
|
+
ER_ROW_IS_REFERENCED_2 = 1451
|
624
590
|
ER_NO_REFERENCED_ROW_2 = 1452
|
625
591
|
ER_DATA_TOO_LONG = 1406
|
626
592
|
ER_OUT_OF_RANGE = 1264
|
@@ -630,35 +596,36 @@ module ActiveRecord
|
|
630
596
|
ER_LOCK_WAIT_TIMEOUT = 1205
|
631
597
|
ER_QUERY_INTERRUPTED = 1317
|
632
598
|
ER_QUERY_TIMEOUT = 3024
|
599
|
+
ER_FK_INCOMPATIBLE_COLUMNS = 3780
|
633
600
|
|
634
|
-
def translate_exception(exception, message)
|
601
|
+
def translate_exception(exception, message:, sql:, binds:)
|
635
602
|
case error_number(exception)
|
636
603
|
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)
|
604
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
605
|
+
when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
|
606
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
607
|
+
when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
|
608
|
+
mismatched_foreign_key(message, sql: sql, binds: binds)
|
642
609
|
when ER_CANNOT_CREATE_TABLE
|
643
610
|
if message.include?("errno: 150")
|
644
|
-
mismatched_foreign_key(message)
|
611
|
+
mismatched_foreign_key(message, sql: sql, binds: binds)
|
645
612
|
else
|
646
613
|
super
|
647
614
|
end
|
648
615
|
when ER_DATA_TOO_LONG
|
649
|
-
ValueTooLong.new(message)
|
616
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
650
617
|
when ER_OUT_OF_RANGE
|
651
|
-
RangeError.new(message)
|
618
|
+
RangeError.new(message, sql: sql, binds: binds)
|
652
619
|
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
653
|
-
NotNullViolation.new(message)
|
620
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
654
621
|
when ER_LOCK_DEADLOCK
|
655
|
-
Deadlocked.new(message)
|
622
|
+
Deadlocked.new(message, sql: sql, binds: binds)
|
656
623
|
when ER_LOCK_WAIT_TIMEOUT
|
657
|
-
LockWaitTimeout.new(message)
|
624
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
658
625
|
when ER_QUERY_TIMEOUT
|
659
|
-
StatementTimeout.new(message)
|
626
|
+
StatementTimeout.new(message, sql: sql, binds: binds)
|
660
627
|
when ER_QUERY_INTERRUPTED
|
661
|
-
QueryCanceled.new(message)
|
628
|
+
QueryCanceled.new(message, sql: sql, binds: binds)
|
662
629
|
else
|
663
630
|
super
|
664
631
|
end
|
@@ -711,6 +678,12 @@ module ActiveRecord
|
|
711
678
|
end
|
712
679
|
|
713
680
|
def add_timestamps_for_alter(table_name, options = {})
|
681
|
+
options[:null] = false if options[:null].nil?
|
682
|
+
|
683
|
+
if !options.key?(:precision) && supports_datetime_with_precision?
|
684
|
+
options[:precision] = 6
|
685
|
+
end
|
686
|
+
|
714
687
|
[add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
|
715
688
|
end
|
716
689
|
|
@@ -718,22 +691,8 @@ module ActiveRecord
|
|
718
691
|
[remove_column_for_alter(table_name, :updated_at), remove_column_for_alter(table_name, :created_at)]
|
719
692
|
end
|
720
693
|
|
721
|
-
# MySQL is too stupid to create a temporary table for use subquery, so we have
|
722
|
-
# to give it some prompting in the form of a subsubquery. Ugh!
|
723
|
-
def subquery_for(key, select)
|
724
|
-
subselect = select.clone
|
725
|
-
subselect.projections = [key]
|
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))
|
733
|
-
end
|
734
|
-
|
735
694
|
def supports_rename_index?
|
736
|
-
mariadb? ? false :
|
695
|
+
mariadb? ? false : database_version >= "5.7.6"
|
737
696
|
end
|
738
697
|
|
739
698
|
def configure_connection
|
@@ -770,7 +729,7 @@ module ActiveRecord
|
|
770
729
|
# https://dev.mysql.com/doc/refman/5.7/en/set-names.html
|
771
730
|
# (trailing comma because variable_assignments will always have content)
|
772
731
|
if @config[:encoding]
|
773
|
-
encoding = "NAMES #{@config[:encoding]}"
|
732
|
+
encoding = +"NAMES #{@config[:encoding]}"
|
774
733
|
encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
|
775
734
|
encoding << ", "
|
776
735
|
end
|
@@ -803,15 +762,21 @@ module ActiveRecord
|
|
803
762
|
Arel::Visitors::MySQL.new(self)
|
804
763
|
end
|
805
764
|
|
806
|
-
def
|
765
|
+
def build_statement_pool
|
766
|
+
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
767
|
+
end
|
768
|
+
|
769
|
+
def mismatched_foreign_key(message, sql:, binds:)
|
807
770
|
match = %r/
|
808
771
|
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
809
772
|
FOREIGN\s+KEY\s*\(`?(?<foreign_key>\w+)`?\)\s*
|
810
773
|
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
811
|
-
/xmi.match(
|
774
|
+
/xmi.match(sql)
|
812
775
|
|
813
776
|
options = {
|
814
777
|
message: message,
|
778
|
+
sql: sql,
|
779
|
+
binds: binds,
|
815
780
|
}
|
816
781
|
|
817
782
|
if match
|
@@ -825,39 +790,8 @@ module ActiveRecord
|
|
825
790
|
MismatchedForeignKey.new(options)
|
826
791
|
end
|
827
792
|
|
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
|
837
|
-
end
|
838
|
-
|
839
|
-
def text_to_sql(limit) # :nodoc:
|
840
|
-
case limit
|
841
|
-
when 0..0xff; "tinytext"
|
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
|
858
|
-
|
859
|
-
def version_string
|
860
|
-
full_version.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
793
|
+
def version_string(full_version_string)
|
794
|
+
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
861
795
|
end
|
862
796
|
|
863
797
|
class MysqlString < Type::String # :nodoc:
|