activerecord 6.0.0 → 6.1.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 +872 -582
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record.rb +7 -13
- data/lib/active_record/aggregations.rb +1 -2
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations.rb +116 -13
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +49 -29
- data/lib/active_record/associations/association_scope.rb +17 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +25 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency.rb +77 -42
- data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/preloader.rb +13 -8
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attributes.rb +32 -8
- data/lib/active_record/autosave_association.rb +63 -44
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +86 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +4 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +263 -107
- data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
- data/lib/active_record/connection_adapters/abstract_adapter.rb +74 -76
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- 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 +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- 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 +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +81 -57
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +211 -81
- data/lib/active_record/core.rb +237 -69
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -41
- 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 +2 -3
- data/lib/active_record/enum.rb +40 -16
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- 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 +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +54 -11
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +39 -10
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +22 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -9
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +70 -20
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/model_schema.rb +120 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/databases.rake +267 -93
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation.rb +108 -67
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +102 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +55 -17
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder.rb +55 -35
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +340 -180
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +104 -58
- data/lib/active_record/result.rb +41 -34
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/scoping/default.rb +0 -1
- data/lib/active_record/scoping/named.rb +7 -18
- 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 +20 -4
- data/lib/active_record/store.rb +3 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -36
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +38 -16
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +22 -71
- data/lib/active_record/type.rb +8 -2
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- 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_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations.rb +3 -3
- 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 +24 -4
- data/lib/arel.rb +15 -12
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/predications.rb +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration.rb +6 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +27 -24
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -45,7 +45,6 @@ module ActiveRecord
|
|
45
45
|
|
46
46
|
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
47
47
|
private
|
48
|
-
|
49
48
|
def dealloc(stmt)
|
50
49
|
stmt.close
|
51
50
|
end
|
@@ -93,6 +92,14 @@ module ActiveRecord
|
|
93
92
|
true
|
94
93
|
end
|
95
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
|
+
|
96
103
|
def supports_views?
|
97
104
|
true
|
98
105
|
end
|
@@ -105,11 +112,19 @@ module ActiveRecord
|
|
105
112
|
mariadb? || database_version >= "5.7.5"
|
106
113
|
end
|
107
114
|
|
108
|
-
# See https://dev.mysql.com/doc/refman/
|
115
|
+
# See https://dev.mysql.com/doc/refman/en/optimizer-hints.html for more details.
|
109
116
|
def supports_optimizer_hints?
|
110
117
|
!mariadb? && database_version >= "5.7.7"
|
111
118
|
end
|
112
119
|
|
120
|
+
def supports_common_table_expressions?
|
121
|
+
if mariadb?
|
122
|
+
database_version >= "10.2.1"
|
123
|
+
else
|
124
|
+
database_version >= "8.0.1"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
113
128
|
def supports_advisory_locks?
|
114
129
|
true
|
115
130
|
end
|
@@ -135,7 +150,12 @@ module ActiveRecord
|
|
135
150
|
end
|
136
151
|
|
137
152
|
def index_algorithms
|
138
|
-
{
|
153
|
+
{
|
154
|
+
default: "ALGORITHM = DEFAULT",
|
155
|
+
copy: "ALGORITHM = COPY",
|
156
|
+
inplace: "ALGORITHM = INPLACE",
|
157
|
+
instant: "ALGORITHM = INSTANT",
|
158
|
+
}
|
139
159
|
end
|
140
160
|
|
141
161
|
# HELPER METHODS ===========================================
|
@@ -176,18 +196,10 @@ module ActiveRecord
|
|
176
196
|
# DATABASE STATEMENTS ======================================
|
177
197
|
#++
|
178
198
|
|
179
|
-
def explain(arel, binds = [])
|
180
|
-
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
181
|
-
start = Concurrent.monotonic_time
|
182
|
-
result = exec_query(sql, "EXPLAIN", binds)
|
183
|
-
elapsed = Concurrent.monotonic_time - start
|
184
|
-
|
185
|
-
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
186
|
-
end
|
187
|
-
|
188
199
|
# Executes the SQL statement in the context of this connection.
|
189
200
|
def execute(sql, name = nil)
|
190
201
|
materialize_transactions
|
202
|
+
mark_transaction_written_if_write(sql)
|
191
203
|
|
192
204
|
log(sql, name) do
|
193
205
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
@@ -204,7 +216,7 @@ module ActiveRecord
|
|
204
216
|
end
|
205
217
|
|
206
218
|
def begin_db_transaction
|
207
|
-
execute
|
219
|
+
execute("BEGIN", "TRANSACTION")
|
208
220
|
end
|
209
221
|
|
210
222
|
def begin_isolated_db_transaction(isolation)
|
@@ -213,11 +225,11 @@ module ActiveRecord
|
|
213
225
|
end
|
214
226
|
|
215
227
|
def commit_db_transaction #:nodoc:
|
216
|
-
execute
|
228
|
+
execute("COMMIT", "TRANSACTION")
|
217
229
|
end
|
218
230
|
|
219
231
|
def exec_rollback_db_transaction #:nodoc:
|
220
|
-
execute
|
232
|
+
execute("ROLLBACK", "TRANSACTION")
|
221
233
|
end
|
222
234
|
|
223
235
|
def empty_insert_statement_value(primary_key = nil)
|
@@ -298,6 +310,8 @@ module ActiveRecord
|
|
298
310
|
# Example:
|
299
311
|
# rename_table('octopuses', 'octopi')
|
300
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)
|
301
315
|
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
302
316
|
rename_table_indexes(table_name, new_name)
|
303
317
|
end
|
@@ -317,7 +331,8 @@ module ActiveRecord
|
|
317
331
|
# Although this command ignores most +options+ and the block if one is given,
|
318
332
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
319
333
|
# In that case, +options+ and the block will be used by create_table.
|
320
|
-
def drop_table(table_name, options
|
334
|
+
def drop_table(table_name, **options)
|
335
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
321
336
|
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
|
322
337
|
end
|
323
338
|
|
@@ -349,8 +364,8 @@ module ActiveRecord
|
|
349
364
|
change_column table_name, column_name, nil, comment: comment
|
350
365
|
end
|
351
366
|
|
352
|
-
def change_column(table_name, column_name, type, options
|
353
|
-
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)}")
|
354
369
|
end
|
355
370
|
|
356
371
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
@@ -358,10 +373,13 @@ module ActiveRecord
|
|
358
373
|
rename_column_indexes(table_name, column_name, new_column_name)
|
359
374
|
end
|
360
375
|
|
361
|
-
def add_index(table_name, column_name, options
|
362
|
-
|
363
|
-
|
364
|
-
|
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)
|
365
383
|
end
|
366
384
|
|
367
385
|
def add_sql_comment!(sql, comment) # :nodoc:
|
@@ -405,24 +423,60 @@ module ActiveRecord
|
|
405
423
|
end
|
406
424
|
end
|
407
425
|
|
408
|
-
def
|
409
|
-
|
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
|
410
453
|
|
454
|
+
def table_options(table_name) # :nodoc:
|
411
455
|
create_table_info = create_table_info(table_name)
|
412
456
|
|
413
457
|
# strip create_definitions and partition_options
|
414
|
-
|
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
|
415
470
|
|
416
471
|
# strip AUTO_INCREMENT
|
417
472
|
raw_table_options.sub!(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1')
|
418
473
|
|
419
|
-
table_options[:options] = raw_table_options
|
420
|
-
|
421
474
|
# strip COMMENT
|
422
475
|
if raw_table_options.sub!(/ COMMENT='.+'/, "")
|
423
476
|
table_options[:comment] = table_comment(table_name)
|
424
477
|
end
|
425
478
|
|
479
|
+
table_options[:options] = raw_table_options unless raw_table_options == "ENGINE=InnoDB"
|
426
480
|
table_options
|
427
481
|
end
|
428
482
|
|
@@ -440,29 +494,14 @@ module ActiveRecord
|
|
440
494
|
|
441
495
|
query_values(<<~SQL, "SCHEMA")
|
442
496
|
SELECT column_name
|
443
|
-
FROM information_schema.
|
444
|
-
WHERE
|
497
|
+
FROM information_schema.statistics
|
498
|
+
WHERE index_name = 'PRIMARY'
|
445
499
|
AND table_schema = #{scope[:schema]}
|
446
500
|
AND table_name = #{scope[:name]}
|
447
|
-
ORDER BY
|
501
|
+
ORDER BY seq_in_index
|
448
502
|
SQL
|
449
503
|
end
|
450
504
|
|
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
505
|
def case_sensitive_comparison(attribute, value) # :nodoc:
|
467
506
|
column = column_for_attribute(attribute)
|
468
507
|
|
@@ -481,14 +520,14 @@ module ActiveRecord
|
|
481
520
|
# In MySQL 5.7.5 and up, ONLY_FULL_GROUP_BY affects handling of queries that use
|
482
521
|
# DISTINCT and ORDER BY. It requires the ORDER BY columns in the select list for
|
483
522
|
# distinct queries, and requires that the ORDER BY include the distinct column.
|
484
|
-
# See https://dev.mysql.com/doc/refman/
|
523
|
+
# See https://dev.mysql.com/doc/refman/en/group-by-handling.html
|
485
524
|
def columns_for_distinct(columns, orders) # :nodoc:
|
486
|
-
order_columns = orders.
|
525
|
+
order_columns = orders.compact_blank.map { |s|
|
487
526
|
# Convert Arel node to string
|
488
|
-
s = s
|
527
|
+
s = visitor.compile(s) unless s.is_a?(String)
|
489
528
|
# Remove any ASC/DESC modifiers
|
490
529
|
s.gsub(/\s+(?:ASC|DESC)\b/i, "")
|
491
|
-
}.
|
530
|
+
}.compact_blank.map.with_index { |column, i| "#{column} AS alias_#{i}" }
|
492
531
|
|
493
532
|
(order_columns << super).join(", ")
|
494
533
|
end
|
@@ -509,6 +548,7 @@ module ActiveRecord
|
|
509
548
|
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
510
549
|
elsif insert.update_duplicates?
|
511
550
|
sql << " ON DUPLICATE KEY UPDATE "
|
551
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
|
512
552
|
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
513
553
|
end
|
514
554
|
|
@@ -522,11 +562,13 @@ module ActiveRecord
|
|
522
562
|
end
|
523
563
|
|
524
564
|
private
|
525
|
-
|
526
565
|
def initialize_type_map(m = type_map)
|
527
566
|
super
|
528
567
|
|
529
|
-
|
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
|
530
572
|
|
531
573
|
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
532
574
|
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
@@ -546,28 +588,19 @@ module ActiveRecord
|
|
546
588
|
register_integer_type m, %r(^tinyint)i, limit: 1
|
547
589
|
|
548
590
|
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
|
549
|
-
m.alias_type %r(year)i,
|
550
|
-
m.alias_type %r(bit)i,
|
591
|
+
m.alias_type %r(year)i, "integer"
|
592
|
+
m.alias_type %r(bit)i, "binary"
|
551
593
|
|
552
|
-
m.register_type
|
553
|
-
|
554
|
-
.split(",").map { |enum| enum.strip.length - 2 }.max
|
555
|
-
MysqlString.new(limit: limit)
|
556
|
-
end
|
557
|
-
|
558
|
-
m.register_type(%r(^set)i) do |sql_type|
|
559
|
-
limit = sql_type[/^set\s*\((.+)\)/i, 1]
|
560
|
-
.split(",").map { |set| set.strip.length - 1 }.sum - 1
|
561
|
-
MysqlString.new(limit: limit)
|
562
|
-
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)
|
563
596
|
end
|
564
597
|
|
565
|
-
def register_integer_type(mapping, key, options)
|
598
|
+
def register_integer_type(mapping, key, **options)
|
566
599
|
mapping.register_type(key) do |sql_type|
|
567
600
|
if /\bunsigned\b/.match?(sql_type)
|
568
|
-
Type::UnsignedInteger.new(options)
|
601
|
+
Type::UnsignedInteger.new(**options)
|
569
602
|
else
|
570
|
-
Type::Integer.new(options)
|
603
|
+
Type::Integer.new(**options)
|
571
604
|
end
|
572
605
|
end
|
573
606
|
end
|
@@ -580,7 +613,9 @@ module ActiveRecord
|
|
580
613
|
end
|
581
614
|
end
|
582
615
|
|
583
|
-
# 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
|
584
619
|
ER_DUP_ENTRY = 1062
|
585
620
|
ER_NOT_NULL_VIOLATION = 1048
|
586
621
|
ER_NO_REFERENCED_ROW = 1216
|
@@ -600,6 +635,14 @@ module ActiveRecord
|
|
600
635
|
|
601
636
|
def translate_exception(exception, message:, sql:, binds:)
|
602
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)
|
603
646
|
when ER_DUP_ENTRY
|
604
647
|
RecordNotUnique.new(message, sql: sql, binds: binds)
|
605
648
|
when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
|
@@ -622,7 +665,7 @@ module ActiveRecord
|
|
622
665
|
Deadlocked.new(message, sql: sql, binds: binds)
|
623
666
|
when ER_LOCK_WAIT_TIMEOUT
|
624
667
|
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
625
|
-
when ER_QUERY_TIMEOUT
|
668
|
+
when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
|
626
669
|
StatementTimeout.new(message, sql: sql, binds: binds)
|
627
670
|
when ER_QUERY_INTERRUPTED
|
628
671
|
QueryCanceled.new(message, sql: sql, binds: binds)
|
@@ -631,7 +674,7 @@ module ActiveRecord
|
|
631
674
|
end
|
632
675
|
end
|
633
676
|
|
634
|
-
def change_column_for_alter(table_name, column_name, type, options
|
677
|
+
def change_column_for_alter(table_name, column_name, type, **options)
|
635
678
|
column = column_for(table_name, column_name)
|
636
679
|
type ||= column.sql_type
|
637
680
|
|
@@ -648,51 +691,53 @@ module ActiveRecord
|
|
648
691
|
end
|
649
692
|
|
650
693
|
td = create_table_definition(table_name)
|
651
|
-
cd = td.new_column_definition(column.name, type, options)
|
694
|
+
cd = td.new_column_definition(column.name, type, **options)
|
652
695
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
653
696
|
end
|
654
697
|
|
655
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
|
+
|
656
701
|
column = column_for(table_name, column_name)
|
657
702
|
options = {
|
658
703
|
default: column.default,
|
659
704
|
null: column.null,
|
660
|
-
auto_increment: column.auto_increment
|
705
|
+
auto_increment: column.auto_increment?,
|
706
|
+
comment: column.comment
|
661
707
|
}
|
662
708
|
|
663
709
|
current_type = exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
|
664
710
|
td = create_table_definition(table_name)
|
665
|
-
cd = td.new_column_definition(new_column_name, current_type, options)
|
711
|
+
cd = td.new_column_definition(new_column_name, current_type, **options)
|
666
712
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
667
713
|
end
|
668
714
|
|
669
|
-
def add_index_for_alter(table_name, column_name, options
|
670
|
-
|
671
|
-
|
672
|
-
|
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
|
718
|
+
|
719
|
+
"ADD #{schema_creation.accept(index)}#{algorithm}"
|
673
720
|
end
|
674
721
|
|
675
|
-
def remove_index_for_alter(table_name,
|
676
|
-
index_name = index_name_for_remove(table_name, options)
|
722
|
+
def remove_index_for_alter(table_name, column_name = nil, **options)
|
723
|
+
index_name = index_name_for_remove(table_name, column_name, options)
|
677
724
|
"DROP INDEX #{quote_column_name(index_name)}"
|
678
725
|
end
|
679
726
|
|
680
|
-
def
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
727
|
+
def supports_rename_index?
|
728
|
+
if mariadb?
|
729
|
+
database_version >= "10.5.2"
|
730
|
+
else
|
731
|
+
database_version >= "5.7.6"
|
685
732
|
end
|
686
|
-
|
687
|
-
[add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
|
688
733
|
end
|
689
734
|
|
690
|
-
def
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
735
|
+
def supports_rename_column?
|
736
|
+
if mariadb?
|
737
|
+
database_version >= "10.5.2"
|
738
|
+
else
|
739
|
+
database_version >= "8.0.3"
|
740
|
+
end
|
696
741
|
end
|
697
742
|
|
698
743
|
def configure_connection
|
@@ -709,7 +754,7 @@ module ActiveRecord
|
|
709
754
|
defaults = [":default", :default].to_set
|
710
755
|
|
711
756
|
# Make MySQL reject illegal values rather than truncating or blanking them, see
|
712
|
-
# https://dev.mysql.com/doc/refman/
|
757
|
+
# https://dev.mysql.com/doc/refman/en/sql-mode.html#sqlmode_strict_all_tables
|
713
758
|
# If the user has provided another value for sql_mode, don't replace it.
|
714
759
|
if sql_mode = variables.delete("sql_mode")
|
715
760
|
sql_mode = quote(sql_mode)
|
@@ -726,7 +771,7 @@ module ActiveRecord
|
|
726
771
|
sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
|
727
772
|
|
728
773
|
# NAMES does not have an equals sign, see
|
729
|
-
# https://dev.mysql.com/doc/refman/
|
774
|
+
# https://dev.mysql.com/doc/refman/en/set-names.html
|
730
775
|
# (trailing comma because variable_assignments will always have content)
|
731
776
|
if @config[:encoding]
|
732
777
|
encoding = +"NAMES #{@config[:encoding]}"
|
@@ -745,7 +790,7 @@ module ActiveRecord
|
|
745
790
|
end.compact.join(", ")
|
746
791
|
|
747
792
|
# ...and send them all in one query
|
748
|
-
execute
|
793
|
+
execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
749
794
|
end
|
750
795
|
|
751
796
|
def column_definitions(table_name) # :nodoc:
|
@@ -787,34 +832,23 @@ module ActiveRecord
|
|
787
832
|
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
788
833
|
end
|
789
834
|
|
790
|
-
MismatchedForeignKey.new(options)
|
835
|
+
MismatchedForeignKey.new(**options)
|
791
836
|
end
|
792
837
|
|
793
838
|
def version_string(full_version_string)
|
794
839
|
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
795
840
|
end
|
796
841
|
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
when true then "1"
|
801
|
-
when false then "0"
|
802
|
-
else super
|
803
|
-
end
|
804
|
-
end
|
805
|
-
|
806
|
-
private
|
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:
|
807
845
|
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
end
|
814
|
-
end
|
846
|
+
ActiveRecord::Type.register(:immutable_string, adapter: :mysql2) do |_, **args|
|
847
|
+
Type::ImmutableString.new(true: "1", false: "0", **args)
|
848
|
+
end
|
849
|
+
ActiveRecord::Type.register(:string, adapter: :mysql2) do |_, **args|
|
850
|
+
Type::String.new(true: "1", false: "0", **args)
|
815
851
|
end
|
816
|
-
|
817
|
-
ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2)
|
818
852
|
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
|
819
853
|
end
|
820
854
|
end
|