activerecord 6.0.1 → 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 +843 -626
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -2
- data/lib/active_record/association_relation.rb +18 -17
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +49 -37
- 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/join_association.rb +36 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +73 -42
- 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/preloader.rb +12 -7
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +115 -12
- data/lib/active_record/attribute_assignment.rb +10 -9
- 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/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +32 -8
- data/lib/active_record/autosave_association.rb +56 -41
- 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/abstract/connection_pool.rb +190 -136
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +82 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -8
- 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 +60 -73
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +136 -111
- 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 +28 -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 +19 -56
- 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/oid.rb +2 -0
- 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 +77 -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 +36 -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 +57 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -87
- data/lib/active_record/core.rb +229 -65
- data/lib/active_record/counter_cache.rb +4 -1
- 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/database_configurations.rb +124 -85
- 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 +2 -2
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +38 -9
- 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/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -2
- data/lib/active_record/middleware/database_selector.rb +4 -2
- 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/migration.rb +114 -84
- data/lib/active_record/model_schema.rb +117 -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/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -32
- 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 +45 -16
- 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/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/predicate_builder.rb +55 -35
- data/lib/active_record/relation/query_methods.rb +335 -187
- 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/relation.rb +108 -68
- 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/default.rb +0 -1
- data/lib/active_record/scoping/named.rb +7 -18
- data/lib/active_record/scoping.rb +0 -1
- 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 +21 -70
- 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.rb +8 -2
- 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/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +7 -13
- 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/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/nodes.rb +3 -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/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/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -9
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- 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/migration.rb +6 -2
- 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 +26 -26
- 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,7 +112,7 @@ 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
|
@@ -143,7 +150,12 @@ module ActiveRecord
|
|
143
150
|
end
|
144
151
|
|
145
152
|
def index_algorithms
|
146
|
-
{
|
153
|
+
{
|
154
|
+
default: "ALGORITHM = DEFAULT",
|
155
|
+
copy: "ALGORITHM = COPY",
|
156
|
+
inplace: "ALGORITHM = INPLACE",
|
157
|
+
instant: "ALGORITHM = INSTANT",
|
158
|
+
}
|
147
159
|
end
|
148
160
|
|
149
161
|
# HELPER METHODS ===========================================
|
@@ -184,18 +196,10 @@ module ActiveRecord
|
|
184
196
|
# DATABASE STATEMENTS ======================================
|
185
197
|
#++
|
186
198
|
|
187
|
-
def explain(arel, binds = [])
|
188
|
-
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
189
|
-
start = Concurrent.monotonic_time
|
190
|
-
result = exec_query(sql, "EXPLAIN", binds)
|
191
|
-
elapsed = Concurrent.monotonic_time - start
|
192
|
-
|
193
|
-
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
194
|
-
end
|
195
|
-
|
196
199
|
# Executes the SQL statement in the context of this connection.
|
197
200
|
def execute(sql, name = nil)
|
198
201
|
materialize_transactions
|
202
|
+
mark_transaction_written_if_write(sql)
|
199
203
|
|
200
204
|
log(sql, name) do
|
201
205
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
@@ -212,7 +216,7 @@ module ActiveRecord
|
|
212
216
|
end
|
213
217
|
|
214
218
|
def begin_db_transaction
|
215
|
-
execute
|
219
|
+
execute("BEGIN", "TRANSACTION")
|
216
220
|
end
|
217
221
|
|
218
222
|
def begin_isolated_db_transaction(isolation)
|
@@ -221,11 +225,11 @@ module ActiveRecord
|
|
221
225
|
end
|
222
226
|
|
223
227
|
def commit_db_transaction #:nodoc:
|
224
|
-
execute
|
228
|
+
execute("COMMIT", "TRANSACTION")
|
225
229
|
end
|
226
230
|
|
227
231
|
def exec_rollback_db_transaction #:nodoc:
|
228
|
-
execute
|
232
|
+
execute("ROLLBACK", "TRANSACTION")
|
229
233
|
end
|
230
234
|
|
231
235
|
def empty_insert_statement_value(primary_key = nil)
|
@@ -306,6 +310,8 @@ module ActiveRecord
|
|
306
310
|
# Example:
|
307
311
|
# rename_table('octopuses', 'octopi')
|
308
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)
|
309
315
|
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
310
316
|
rename_table_indexes(table_name, new_name)
|
311
317
|
end
|
@@ -325,7 +331,8 @@ module ActiveRecord
|
|
325
331
|
# Although this command ignores most +options+ and the block if one is given,
|
326
332
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
327
333
|
# In that case, +options+ and the block will be used by create_table.
|
328
|
-
def drop_table(table_name, options
|
334
|
+
def drop_table(table_name, **options)
|
335
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
329
336
|
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
|
330
337
|
end
|
331
338
|
|
@@ -357,8 +364,8 @@ module ActiveRecord
|
|
357
364
|
change_column table_name, column_name, nil, comment: comment
|
358
365
|
end
|
359
366
|
|
360
|
-
def change_column(table_name, column_name, type, options
|
361
|
-
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)}")
|
362
369
|
end
|
363
370
|
|
364
371
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
@@ -366,10 +373,13 @@ module ActiveRecord
|
|
366
373
|
rename_column_indexes(table_name, column_name, new_column_name)
|
367
374
|
end
|
368
375
|
|
369
|
-
def add_index(table_name, column_name, options
|
370
|
-
|
371
|
-
|
372
|
-
|
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)
|
373
383
|
end
|
374
384
|
|
375
385
|
def add_sql_comment!(sql, comment) # :nodoc:
|
@@ -413,24 +423,60 @@ module ActiveRecord
|
|
413
423
|
end
|
414
424
|
end
|
415
425
|
|
416
|
-
def
|
417
|
-
|
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
|
418
453
|
|
454
|
+
def table_options(table_name) # :nodoc:
|
419
455
|
create_table_info = create_table_info(table_name)
|
420
456
|
|
421
457
|
# strip create_definitions and partition_options
|
422
|
-
|
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
|
423
470
|
|
424
471
|
# strip AUTO_INCREMENT
|
425
472
|
raw_table_options.sub!(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1')
|
426
473
|
|
427
|
-
table_options[:options] = raw_table_options
|
428
|
-
|
429
474
|
# strip COMMENT
|
430
475
|
if raw_table_options.sub!(/ COMMENT='.+'/, "")
|
431
476
|
table_options[:comment] = table_comment(table_name)
|
432
477
|
end
|
433
478
|
|
479
|
+
table_options[:options] = raw_table_options unless raw_table_options == "ENGINE=InnoDB"
|
434
480
|
table_options
|
435
481
|
end
|
436
482
|
|
@@ -456,21 +502,6 @@ module ActiveRecord
|
|
456
502
|
SQL
|
457
503
|
end
|
458
504
|
|
459
|
-
def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
|
460
|
-
column = column_for_attribute(attribute)
|
461
|
-
|
462
|
-
if column.collation && !column.case_sensitive? && !value.nil?
|
463
|
-
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
464
|
-
Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1.
|
465
|
-
To continue case sensitive comparison on the :#{attribute.name} attribute in #{klass} model,
|
466
|
-
pass `case_sensitive: true` option explicitly to the uniqueness validator.
|
467
|
-
MSG
|
468
|
-
attribute.eq(Arel::Nodes::Bin.new(value))
|
469
|
-
else
|
470
|
-
super
|
471
|
-
end
|
472
|
-
end
|
473
|
-
|
474
505
|
def case_sensitive_comparison(attribute, value) # :nodoc:
|
475
506
|
column = column_for_attribute(attribute)
|
476
507
|
|
@@ -489,14 +520,14 @@ module ActiveRecord
|
|
489
520
|
# In MySQL 5.7.5 and up, ONLY_FULL_GROUP_BY affects handling of queries that use
|
490
521
|
# DISTINCT and ORDER BY. It requires the ORDER BY columns in the select list for
|
491
522
|
# distinct queries, and requires that the ORDER BY include the distinct column.
|
492
|
-
# See https://dev.mysql.com/doc/refman/
|
523
|
+
# See https://dev.mysql.com/doc/refman/en/group-by-handling.html
|
493
524
|
def columns_for_distinct(columns, orders) # :nodoc:
|
494
|
-
order_columns = orders.
|
525
|
+
order_columns = orders.compact_blank.map { |s|
|
495
526
|
# Convert Arel node to string
|
496
|
-
s = s
|
527
|
+
s = visitor.compile(s) unless s.is_a?(String)
|
497
528
|
# Remove any ASC/DESC modifiers
|
498
529
|
s.gsub(/\s+(?:ASC|DESC)\b/i, "")
|
499
|
-
}.
|
530
|
+
}.compact_blank.map.with_index { |column, i| "#{column} AS alias_#{i}" }
|
500
531
|
|
501
532
|
(order_columns << super).join(", ")
|
502
533
|
end
|
@@ -517,6 +548,7 @@ module ActiveRecord
|
|
517
548
|
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
518
549
|
elsif insert.update_duplicates?
|
519
550
|
sql << " ON DUPLICATE KEY UPDATE "
|
551
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
|
520
552
|
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
521
553
|
end
|
522
554
|
|
@@ -530,11 +562,13 @@ module ActiveRecord
|
|
530
562
|
end
|
531
563
|
|
532
564
|
private
|
533
|
-
|
534
565
|
def initialize_type_map(m = type_map)
|
535
566
|
super
|
536
567
|
|
537
|
-
|
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
|
538
572
|
|
539
573
|
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
540
574
|
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
@@ -554,28 +588,19 @@ module ActiveRecord
|
|
554
588
|
register_integer_type m, %r(^tinyint)i, limit: 1
|
555
589
|
|
556
590
|
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
|
557
|
-
m.alias_type %r(year)i,
|
558
|
-
m.alias_type %r(bit)i,
|
559
|
-
|
560
|
-
m.register_type(%r(enum)i) do |sql_type|
|
561
|
-
limit = sql_type[/^enum\s*\((.+)\)/i, 1]
|
562
|
-
.split(",").map { |enum| enum.strip.length - 2 }.max
|
563
|
-
MysqlString.new(limit: limit)
|
564
|
-
end
|
591
|
+
m.alias_type %r(year)i, "integer"
|
592
|
+
m.alias_type %r(bit)i, "binary"
|
565
593
|
|
566
|
-
m.register_type
|
567
|
-
|
568
|
-
.split(",").map { |set| set.strip.length - 1 }.sum - 1
|
569
|
-
MysqlString.new(limit: limit)
|
570
|
-
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)
|
571
596
|
end
|
572
597
|
|
573
|
-
def register_integer_type(mapping, key, options)
|
598
|
+
def register_integer_type(mapping, key, **options)
|
574
599
|
mapping.register_type(key) do |sql_type|
|
575
600
|
if /\bunsigned\b/.match?(sql_type)
|
576
|
-
Type::UnsignedInteger.new(options)
|
601
|
+
Type::UnsignedInteger.new(**options)
|
577
602
|
else
|
578
|
-
Type::Integer.new(options)
|
603
|
+
Type::Integer.new(**options)
|
579
604
|
end
|
580
605
|
end
|
581
606
|
end
|
@@ -588,7 +613,8 @@ module ActiveRecord
|
|
588
613
|
end
|
589
614
|
end
|
590
615
|
|
591
|
-
# 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
|
592
618
|
ER_FILSORT_ABORT = 1028
|
593
619
|
ER_DUP_ENTRY = 1062
|
594
620
|
ER_NOT_NULL_VIOLATION = 1048
|
@@ -609,6 +635,14 @@ module ActiveRecord
|
|
609
635
|
|
610
636
|
def translate_exception(exception, message:, sql:, binds:)
|
611
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)
|
612
646
|
when ER_DUP_ENTRY
|
613
647
|
RecordNotUnique.new(message, sql: sql, binds: binds)
|
614
648
|
when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
|
@@ -640,7 +674,7 @@ module ActiveRecord
|
|
640
674
|
end
|
641
675
|
end
|
642
676
|
|
643
|
-
def change_column_for_alter(table_name, column_name, type, options
|
677
|
+
def change_column_for_alter(table_name, column_name, type, **options)
|
644
678
|
column = column_for(table_name, column_name)
|
645
679
|
type ||= column.sql_type
|
646
680
|
|
@@ -657,51 +691,53 @@ module ActiveRecord
|
|
657
691
|
end
|
658
692
|
|
659
693
|
td = create_table_definition(table_name)
|
660
|
-
cd = td.new_column_definition(column.name, type, options)
|
694
|
+
cd = td.new_column_definition(column.name, type, **options)
|
661
695
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
662
696
|
end
|
663
697
|
|
664
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
|
+
|
665
701
|
column = column_for(table_name, column_name)
|
666
702
|
options = {
|
667
703
|
default: column.default,
|
668
704
|
null: column.null,
|
669
|
-
auto_increment: column.auto_increment
|
705
|
+
auto_increment: column.auto_increment?,
|
706
|
+
comment: column.comment
|
670
707
|
}
|
671
708
|
|
672
709
|
current_type = exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
|
673
710
|
td = create_table_definition(table_name)
|
674
|
-
cd = td.new_column_definition(new_column_name, current_type, options)
|
711
|
+
cd = td.new_column_definition(new_column_name, current_type, **options)
|
675
712
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
676
713
|
end
|
677
714
|
|
678
|
-
def add_index_for_alter(table_name, column_name, options
|
679
|
-
|
680
|
-
|
681
|
-
|
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}"
|
682
720
|
end
|
683
721
|
|
684
|
-
def remove_index_for_alter(table_name,
|
685
|
-
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)
|
686
724
|
"DROP INDEX #{quote_column_name(index_name)}"
|
687
725
|
end
|
688
726
|
|
689
|
-
def
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
727
|
+
def supports_rename_index?
|
728
|
+
if mariadb?
|
729
|
+
database_version >= "10.5.2"
|
730
|
+
else
|
731
|
+
database_version >= "5.7.6"
|
694
732
|
end
|
695
|
-
|
696
|
-
[add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
|
697
733
|
end
|
698
734
|
|
699
|
-
def
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
735
|
+
def supports_rename_column?
|
736
|
+
if mariadb?
|
737
|
+
database_version >= "10.5.2"
|
738
|
+
else
|
739
|
+
database_version >= "8.0.3"
|
740
|
+
end
|
705
741
|
end
|
706
742
|
|
707
743
|
def configure_connection
|
@@ -718,7 +754,7 @@ module ActiveRecord
|
|
718
754
|
defaults = [":default", :default].to_set
|
719
755
|
|
720
756
|
# Make MySQL reject illegal values rather than truncating or blanking them, see
|
721
|
-
# https://dev.mysql.com/doc/refman/
|
757
|
+
# https://dev.mysql.com/doc/refman/en/sql-mode.html#sqlmode_strict_all_tables
|
722
758
|
# If the user has provided another value for sql_mode, don't replace it.
|
723
759
|
if sql_mode = variables.delete("sql_mode")
|
724
760
|
sql_mode = quote(sql_mode)
|
@@ -735,7 +771,7 @@ module ActiveRecord
|
|
735
771
|
sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
|
736
772
|
|
737
773
|
# NAMES does not have an equals sign, see
|
738
|
-
# https://dev.mysql.com/doc/refman/
|
774
|
+
# https://dev.mysql.com/doc/refman/en/set-names.html
|
739
775
|
# (trailing comma because variable_assignments will always have content)
|
740
776
|
if @config[:encoding]
|
741
777
|
encoding = +"NAMES #{@config[:encoding]}"
|
@@ -754,7 +790,7 @@ module ActiveRecord
|
|
754
790
|
end.compact.join(", ")
|
755
791
|
|
756
792
|
# ...and send them all in one query
|
757
|
-
execute
|
793
|
+
execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
758
794
|
end
|
759
795
|
|
760
796
|
def column_definitions(table_name) # :nodoc:
|
@@ -796,34 +832,23 @@ module ActiveRecord
|
|
796
832
|
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
797
833
|
end
|
798
834
|
|
799
|
-
MismatchedForeignKey.new(options)
|
835
|
+
MismatchedForeignKey.new(**options)
|
800
836
|
end
|
801
837
|
|
802
838
|
def version_string(full_version_string)
|
803
839
|
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
804
840
|
end
|
805
841
|
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
when true then "1"
|
810
|
-
when false then "0"
|
811
|
-
else super
|
812
|
-
end
|
813
|
-
end
|
814
|
-
|
815
|
-
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:
|
816
845
|
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
end
|
823
|
-
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)
|
824
851
|
end
|
825
|
-
|
826
|
-
ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2)
|
827
852
|
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
|
828
853
|
end
|
829
854
|
end
|
@@ -5,6 +5,8 @@ module ActiveRecord
|
|
5
5
|
module ConnectionAdapters
|
6
6
|
# An abstract definition of a column in a table.
|
7
7
|
class Column
|
8
|
+
include Deduplicable
|
9
|
+
|
8
10
|
attr_reader :name, :default, :sql_type_metadata, :null, :default_function, :collation, :comment
|
9
11
|
|
10
12
|
delegate :precision, :scale, :limit, :type, :sql_type, to: :sql_type_metadata, allow_nil: true
|
@@ -76,6 +78,7 @@ module ActiveRecord
|
|
76
78
|
def hash
|
77
79
|
Column.hash ^
|
78
80
|
name.hash ^
|
81
|
+
name.encoding.hash ^
|
79
82
|
default.hash ^
|
80
83
|
sql_type_metadata.hash ^
|
81
84
|
null.hash ^
|
@@ -83,10 +86,21 @@ module ActiveRecord
|
|
83
86
|
collation.hash ^
|
84
87
|
comment.hash
|
85
88
|
end
|
89
|
+
|
90
|
+
private
|
91
|
+
def deduplicated
|
92
|
+
@name = -name
|
93
|
+
@sql_type_metadata = sql_type_metadata.deduplicate if sql_type_metadata
|
94
|
+
@default = -default if default
|
95
|
+
@default_function = -default_function if default_function
|
96
|
+
@collation = -collation if collation
|
97
|
+
@comment = -comment if comment
|
98
|
+
super
|
99
|
+
end
|
86
100
|
end
|
87
101
|
|
88
102
|
class NullColumn < Column
|
89
|
-
def initialize(name)
|
103
|
+
def initialize(name, **)
|
90
104
|
super(name, nil)
|
91
105
|
end
|
92
106
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters # :nodoc:
|
5
|
+
module Deduplicable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def registry
|
10
|
+
@registry ||= {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def new(*, **)
|
14
|
+
super.deduplicate
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def deduplicate
|
19
|
+
self.class.registry[self] ||= deduplicated
|
20
|
+
end
|
21
|
+
alias :-@ :deduplicate
|
22
|
+
|
23
|
+
private
|
24
|
+
def deduplicated
|
25
|
+
freeze
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
class LegacyPoolManager # :nodoc:
|
6
|
+
def initialize
|
7
|
+
@name_to_pool_config = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def shard_names
|
11
|
+
@name_to_pool_config.keys
|
12
|
+
end
|
13
|
+
|
14
|
+
def pool_configs(_ = nil)
|
15
|
+
@name_to_pool_config.values
|
16
|
+
end
|
17
|
+
|
18
|
+
def remove_pool_config(_, shard)
|
19
|
+
@name_to_pool_config.delete(shard)
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_pool_config(_, shard)
|
23
|
+
@name_to_pool_config[shard]
|
24
|
+
end
|
25
|
+
|
26
|
+
def set_pool_config(_, shard, pool_config)
|
27
|
+
@name_to_pool_config[shard] = pool_config
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|