activerecord 6.0.3.4 → 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 +799 -713
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/active_record.rb +7 -14
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +44 -28
- 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 -1
- 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 +19 -6
- data/lib/active_record/associations/collection_proxy.rb +13 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- 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 +72 -50
- 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 +11 -5
- 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 -8
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +11 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attributes.rb +32 -7
- data/lib/active_record/autosave_association.rb +57 -40
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +152 -22
- data/lib/active_record/coders/yaml_column.rb +1 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +191 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- 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 +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +112 -27
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
- data/lib/active_record/connection_adapters/abstract_adapter.rb +54 -71
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +129 -88
- 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/database_statements.rb +23 -25
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
- 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 +11 -7
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- 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 +13 -54
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- 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/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -5
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
- 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 +31 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +37 -4
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +49 -50
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +229 -63
- 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 -40
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +40 -16
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- 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 -2
- data/lib/active_record/fixtures.rb +54 -8
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +35 -6
- 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 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -8
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/model_schema.rb +117 -13
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/databases.rake +266 -95
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +71 -57
- data/lib/active_record/relation.rb +96 -67
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +101 -44
- data/lib/active_record/relation/delegation.rb +2 -1
- data/lib/active_record/relation/finder_methods.rb +45 -15
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +27 -25
- data/lib/active_record/relation/predicate_builder.rb +57 -33
- 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 +330 -195
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/result.rb +41 -33
- 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/named.rb +6 -17
- 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 +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -51
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +37 -16
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type/time.rb +10 -0
- 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 +1 -0
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/arel.rb +5 -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.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 +12 -18
- 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 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/rails/generators/active_record/migration.rb +6 -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 +3 -3
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +27 -28
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- 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 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
@@ -5,10 +5,11 @@ module ActiveRecord
|
|
5
5
|
class TransactionState
|
6
6
|
def initialize(state = nil)
|
7
7
|
@state = state
|
8
|
-
@children =
|
8
|
+
@children = nil
|
9
9
|
end
|
10
10
|
|
11
11
|
def add_child(state)
|
12
|
+
@children ||= []
|
12
13
|
@children << state
|
13
14
|
end
|
14
15
|
|
@@ -41,12 +42,12 @@ module ActiveRecord
|
|
41
42
|
end
|
42
43
|
|
43
44
|
def rollback!
|
44
|
-
@children
|
45
|
+
@children&.each { |c| c.rollback! }
|
45
46
|
@state = :rolledback
|
46
47
|
end
|
47
48
|
|
48
49
|
def full_rollback!
|
49
|
-
@children
|
50
|
+
@children&.each { |c| c.rollback! }
|
50
51
|
@state = :fully_rolledback
|
51
52
|
end
|
52
53
|
|
@@ -69,24 +70,40 @@ module ActiveRecord
|
|
69
70
|
def closed?; true; end
|
70
71
|
def open?; false; end
|
71
72
|
def joinable?; false; end
|
72
|
-
def add_record(record); end
|
73
|
+
def add_record(record, _ = true); end
|
73
74
|
end
|
74
75
|
|
75
76
|
class Transaction #:nodoc:
|
76
|
-
attr_reader :connection, :state, :
|
77
|
+
attr_reader :connection, :state, :savepoint_name, :isolation_level
|
78
|
+
attr_accessor :written
|
77
79
|
|
78
|
-
def initialize(connection,
|
80
|
+
def initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false)
|
79
81
|
@connection = connection
|
80
82
|
@state = TransactionState.new
|
81
|
-
@records =
|
82
|
-
@isolation_level =
|
83
|
+
@records = nil
|
84
|
+
@isolation_level = isolation
|
83
85
|
@materialized = false
|
84
|
-
@joinable =
|
86
|
+
@joinable = joinable
|
85
87
|
@run_commit_callbacks = run_commit_callbacks
|
88
|
+
@lazy_enrollment_records = nil
|
86
89
|
end
|
87
90
|
|
88
|
-
def add_record(record)
|
89
|
-
records
|
91
|
+
def add_record(record, ensure_finalize = true)
|
92
|
+
@records ||= []
|
93
|
+
if ensure_finalize
|
94
|
+
@records << record
|
95
|
+
else
|
96
|
+
@lazy_enrollment_records ||= ObjectSpace::WeakMap.new
|
97
|
+
@lazy_enrollment_records[record] = record
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def records
|
102
|
+
if @lazy_enrollment_records
|
103
|
+
@records.concat @lazy_enrollment_records.values
|
104
|
+
@lazy_enrollment_records = nil
|
105
|
+
end
|
106
|
+
@records
|
90
107
|
end
|
91
108
|
|
92
109
|
def materialize!
|
@@ -98,6 +115,7 @@ module ActiveRecord
|
|
98
115
|
end
|
99
116
|
|
100
117
|
def rollback_records
|
118
|
+
return unless records
|
101
119
|
ite = records.uniq(&:__id__)
|
102
120
|
already_run_callbacks = {}
|
103
121
|
while record = ite.shift
|
@@ -107,16 +125,17 @@ module ActiveRecord
|
|
107
125
|
record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks)
|
108
126
|
end
|
109
127
|
ensure
|
110
|
-
ite
|
128
|
+
ite&.each do |i|
|
111
129
|
i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
|
112
130
|
end
|
113
131
|
end
|
114
132
|
|
115
133
|
def before_commit_records
|
116
|
-
records.uniq.each(&:before_committed!) if @run_commit_callbacks
|
134
|
+
records.uniq.each(&:before_committed!) if records && @run_commit_callbacks
|
117
135
|
end
|
118
136
|
|
119
137
|
def commit_records
|
138
|
+
return unless records
|
120
139
|
ite = records.uniq(&:__id__)
|
121
140
|
already_run_callbacks = {}
|
122
141
|
while record = ite.shift
|
@@ -131,7 +150,7 @@ module ActiveRecord
|
|
131
150
|
end
|
132
151
|
end
|
133
152
|
ensure
|
134
|
-
ite
|
153
|
+
ite&.each { |i| i.committed!(should_run_callbacks: false) }
|
135
154
|
end
|
136
155
|
|
137
156
|
def full_rollback?; true; end
|
@@ -141,8 +160,8 @@ module ActiveRecord
|
|
141
160
|
end
|
142
161
|
|
143
162
|
class SavepointTransaction < Transaction
|
144
|
-
def initialize(connection, savepoint_name, parent_transaction,
|
145
|
-
super(connection,
|
163
|
+
def initialize(connection, savepoint_name, parent_transaction, **options)
|
164
|
+
super(connection, **options)
|
146
165
|
|
147
166
|
parent_transaction.state.add_child(@state)
|
148
167
|
|
@@ -202,18 +221,29 @@ module ActiveRecord
|
|
202
221
|
@lazy_transactions_enabled = true
|
203
222
|
end
|
204
223
|
|
205
|
-
def begin_transaction(
|
224
|
+
def begin_transaction(isolation: nil, joinable: true, _lazy: true)
|
206
225
|
@connection.lock.synchronize do
|
207
226
|
run_commit_callbacks = !current_transaction.joinable?
|
208
227
|
transaction =
|
209
228
|
if @stack.empty?
|
210
|
-
RealTransaction.new(
|
229
|
+
RealTransaction.new(
|
230
|
+
@connection,
|
231
|
+
isolation: isolation,
|
232
|
+
joinable: joinable,
|
233
|
+
run_commit_callbacks: run_commit_callbacks
|
234
|
+
)
|
211
235
|
else
|
212
|
-
SavepointTransaction.new(
|
213
|
-
|
236
|
+
SavepointTransaction.new(
|
237
|
+
@connection,
|
238
|
+
"active_record_#{@stack.size}",
|
239
|
+
@stack.last,
|
240
|
+
isolation: isolation,
|
241
|
+
joinable: joinable,
|
242
|
+
run_commit_callbacks: run_commit_callbacks
|
243
|
+
)
|
214
244
|
end
|
215
245
|
|
216
|
-
if @connection.supports_lazy_transactions? && lazy_transactions_enabled? &&
|
246
|
+
if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && _lazy
|
217
247
|
@has_unmaterialized_transactions = true
|
218
248
|
else
|
219
249
|
transaction.materialize!
|
@@ -274,10 +304,12 @@ module ActiveRecord
|
|
274
304
|
end
|
275
305
|
end
|
276
306
|
|
277
|
-
def within_new_transaction(
|
307
|
+
def within_new_transaction(isolation: nil, joinable: true)
|
278
308
|
@connection.lock.synchronize do
|
279
|
-
transaction = begin_transaction
|
280
|
-
yield
|
309
|
+
transaction = begin_transaction(isolation: isolation, joinable: joinable)
|
310
|
+
ret = yield
|
311
|
+
completed = true
|
312
|
+
ret
|
281
313
|
rescue Exception => error
|
282
314
|
if transaction
|
283
315
|
rollback_transaction
|
@@ -285,15 +317,31 @@ module ActiveRecord
|
|
285
317
|
end
|
286
318
|
raise
|
287
319
|
ensure
|
288
|
-
if
|
289
|
-
if
|
290
|
-
|
320
|
+
if transaction
|
321
|
+
if error
|
322
|
+
# @connection still holds an open transaction, so we must not
|
323
|
+
# put it back in the pool for reuse
|
324
|
+
@connection.throw_away! unless transaction.state.rolledback?
|
291
325
|
else
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
326
|
+
if Thread.current.status == "aborting"
|
327
|
+
rollback_transaction
|
328
|
+
else
|
329
|
+
if !completed && transaction.written
|
330
|
+
ActiveSupport::Deprecation.warn(<<~EOW)
|
331
|
+
Using `return`, `break` or `throw` to exit a transaction block is
|
332
|
+
deprecated without replacement. If the `throw` came from
|
333
|
+
`Timeout.timeout(duration)`, pass an exception class as a second
|
334
|
+
argument so it doesn't use `throw` to abort its block. This results
|
335
|
+
in the transaction being committed, but in the next release of Rails
|
336
|
+
it will rollback.
|
337
|
+
EOW
|
338
|
+
end
|
339
|
+
begin
|
340
|
+
commit_transaction
|
341
|
+
rescue Exception
|
342
|
+
rollback_transaction(transaction) unless transaction.state.completed?
|
343
|
+
raise
|
344
|
+
end
|
297
345
|
end
|
298
346
|
end
|
299
347
|
end
|
@@ -1,13 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "set"
|
4
|
-
require "active_record/connection_adapters/determine_if_preparable_visitor"
|
5
4
|
require "active_record/connection_adapters/schema_cache"
|
6
5
|
require "active_record/connection_adapters/sql_type_metadata"
|
7
6
|
require "active_record/connection_adapters/abstract/schema_dumper"
|
8
7
|
require "active_record/connection_adapters/abstract/schema_creation"
|
9
8
|
require "active_support/concurrency/load_interlock_aware_monitor"
|
10
|
-
require "active_support/deprecation"
|
11
9
|
require "arel/collectors/bind"
|
12
10
|
require "arel/collectors/composite"
|
13
11
|
require "arel/collectors/sql_string"
|
@@ -15,44 +13,6 @@ require "arel/collectors/substitute_binds"
|
|
15
13
|
|
16
14
|
module ActiveRecord
|
17
15
|
module ConnectionAdapters # :nodoc:
|
18
|
-
extend ActiveSupport::Autoload
|
19
|
-
|
20
|
-
autoload :Column
|
21
|
-
autoload :ConnectionSpecification
|
22
|
-
|
23
|
-
autoload_at "active_record/connection_adapters/abstract/schema_definitions" do
|
24
|
-
autoload :IndexDefinition
|
25
|
-
autoload :ColumnDefinition
|
26
|
-
autoload :ChangeColumnDefinition
|
27
|
-
autoload :ForeignKeyDefinition
|
28
|
-
autoload :TableDefinition
|
29
|
-
autoload :Table
|
30
|
-
autoload :AlterTable
|
31
|
-
autoload :ReferenceDefinition
|
32
|
-
end
|
33
|
-
|
34
|
-
autoload_at "active_record/connection_adapters/abstract/connection_pool" do
|
35
|
-
autoload :ConnectionHandler
|
36
|
-
end
|
37
|
-
|
38
|
-
autoload_under "abstract" do
|
39
|
-
autoload :SchemaStatements
|
40
|
-
autoload :DatabaseStatements
|
41
|
-
autoload :DatabaseLimits
|
42
|
-
autoload :Quoting
|
43
|
-
autoload :ConnectionPool
|
44
|
-
autoload :QueryCache
|
45
|
-
autoload :Savepoints
|
46
|
-
end
|
47
|
-
|
48
|
-
autoload_at "active_record/connection_adapters/abstract/transaction" do
|
49
|
-
autoload :TransactionManager
|
50
|
-
autoload :NullTransaction
|
51
|
-
autoload :RealTransaction
|
52
|
-
autoload :SavepointTransaction
|
53
|
-
autoload :TransactionState
|
54
|
-
end
|
55
|
-
|
56
16
|
# Active Record supports multiple database systems. AbstractAdapter and
|
57
17
|
# related classes form the abstraction layer which makes this possible.
|
58
18
|
# An AbstractAdapter represents a connection to a database, and provides an
|
@@ -77,7 +37,7 @@ module ActiveRecord
|
|
77
37
|
include Savepoints
|
78
38
|
|
79
39
|
SIMPLE_INT = /\A\d+\z/
|
80
|
-
COMMENT_REGEX = %r{
|
40
|
+
COMMENT_REGEX = %r{(?:\-\-.*\n)*|/\*(?:[^\*]|\*[^/])*\*/}m
|
81
41
|
|
82
42
|
attr_accessor :pool
|
83
43
|
attr_reader :visitor, :owner, :logger, :lock
|
@@ -103,7 +63,11 @@ module ActiveRecord
|
|
103
63
|
end
|
104
64
|
end
|
105
65
|
|
66
|
+
DEFAULT_READ_QUERY = [:begin, :commit, :explain, :release, :rollback, :savepoint, :select, :with] # :nodoc:
|
67
|
+
private_constant :DEFAULT_READ_QUERY
|
68
|
+
|
106
69
|
def self.build_read_query_regexp(*parts) # :nodoc:
|
70
|
+
parts += DEFAULT_READ_QUERY
|
107
71
|
parts = parts.map { |part| /#{part}/i }
|
108
72
|
/\A(?:[\(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
|
109
73
|
end
|
@@ -130,12 +94,9 @@ module ActiveRecord
|
|
130
94
|
@statements = build_statement_pool
|
131
95
|
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
132
96
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
else
|
137
|
-
@prepared_statements = false
|
138
|
-
end
|
97
|
+
@prepared_statements = self.class.type_cast_config_to_boolean(
|
98
|
+
config.fetch(:prepared_statements, true)
|
99
|
+
)
|
139
100
|
|
140
101
|
@advisory_locks_enabled = self.class.type_cast_config_to_boolean(
|
141
102
|
config.fetch(:advisory_locks, true)
|
@@ -146,12 +107,26 @@ module ActiveRecord
|
|
146
107
|
@config[:replica] || false
|
147
108
|
end
|
148
109
|
|
110
|
+
def use_metadata_table?
|
111
|
+
@config.fetch(:use_metadata_table, true)
|
112
|
+
end
|
113
|
+
|
149
114
|
# Determines whether writes are currently being prevents.
|
150
115
|
#
|
151
|
-
# Returns true if the connection is a replica
|
152
|
-
#
|
116
|
+
# Returns true if the connection is a replica.
|
117
|
+
#
|
118
|
+
# If the application is using legacy handling, returns
|
119
|
+
# true if `connection_handler.prevent_writes` is set.
|
120
|
+
#
|
121
|
+
# If the application is using the new connection handling
|
122
|
+
# will return true based on `current_preventing_writes`.
|
153
123
|
def preventing_writes?
|
154
|
-
replica?
|
124
|
+
return true if replica?
|
125
|
+
return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord::Base.legacy_connection_handling
|
126
|
+
return false if owner_name.nil?
|
127
|
+
|
128
|
+
klass = self.owner_name.safe_constantize
|
129
|
+
klass&.current_preventing_writes
|
155
130
|
end
|
156
131
|
|
157
132
|
def migrations_paths # :nodoc:
|
@@ -165,12 +140,15 @@ module ActiveRecord
|
|
165
140
|
def schema_migration # :nodoc:
|
166
141
|
@schema_migration ||= begin
|
167
142
|
conn = self
|
168
|
-
spec_name = conn.pool.
|
169
|
-
|
143
|
+
spec_name = conn.pool.pool_config.connection_specification_name
|
144
|
+
|
145
|
+
return ActiveRecord::SchemaMigration if spec_name == "ActiveRecord::Base"
|
146
|
+
|
147
|
+
schema_migration_name = "#{spec_name}::SchemaMigration"
|
170
148
|
|
171
149
|
Class.new(ActiveRecord::SchemaMigration) do
|
172
|
-
define_singleton_method(:name) {
|
173
|
-
define_singleton_method(:to_s) {
|
150
|
+
define_singleton_method(:name) { schema_migration_name }
|
151
|
+
define_singleton_method(:to_s) { schema_migration_name }
|
174
152
|
|
175
153
|
self.connection_specification_name = spec_name
|
176
154
|
end
|
@@ -224,6 +202,10 @@ module ActiveRecord
|
|
224
202
|
@owner = Thread.current
|
225
203
|
end
|
226
204
|
|
205
|
+
def owner_name # :nodoc:
|
206
|
+
@pool.owner_name
|
207
|
+
end
|
208
|
+
|
227
209
|
def schema_cache
|
228
210
|
@pool.get_schema_cache(self)
|
229
211
|
end
|
@@ -363,12 +345,10 @@ module ActiveRecord
|
|
363
345
|
false
|
364
346
|
end
|
365
347
|
|
366
|
-
# Does this adapter support creating
|
367
|
-
|
368
|
-
|
369
|
-
supports_foreign_keys?
|
348
|
+
# Does this adapter support creating check constraints?
|
349
|
+
def supports_check_constraints?
|
350
|
+
false
|
370
351
|
end
|
371
|
-
deprecate :supports_foreign_keys_in_create?
|
372
352
|
|
373
353
|
# Does this adapter support views?
|
374
354
|
def supports_views?
|
@@ -400,12 +380,6 @@ module ActiveRecord
|
|
400
380
|
false
|
401
381
|
end
|
402
382
|
|
403
|
-
# Does this adapter support multi-value insert?
|
404
|
-
def supports_multi_insert?
|
405
|
-
true
|
406
|
-
end
|
407
|
-
deprecate :supports_multi_insert?
|
408
|
-
|
409
383
|
# Does this adapter support virtual columns?
|
410
384
|
def supports_virtual_columns?
|
411
385
|
false
|
@@ -537,6 +511,12 @@ module ActiveRecord
|
|
537
511
|
# this should be overridden by concrete adapters
|
538
512
|
end
|
539
513
|
|
514
|
+
# Removes the connection from the pool and disconnect it.
|
515
|
+
def throw_away!
|
516
|
+
pool.remove self
|
517
|
+
disconnect!
|
518
|
+
end
|
519
|
+
|
540
520
|
# Clear any caching the database adapter may be doing.
|
541
521
|
def clear_cache!
|
542
522
|
@lock.synchronize { @statements.clear } if @statements
|
@@ -565,7 +545,7 @@ module ActiveRecord
|
|
565
545
|
@connection
|
566
546
|
end
|
567
547
|
|
568
|
-
def default_uniqueness_comparison(attribute, value
|
548
|
+
def default_uniqueness_comparison(attribute, value) # :nodoc:
|
569
549
|
attribute.eq(value)
|
570
550
|
end
|
571
551
|
|
@@ -593,10 +573,6 @@ module ActiveRecord
|
|
593
573
|
pool.checkin self
|
594
574
|
end
|
595
575
|
|
596
|
-
def column_name_for_operation(operation, node) # :nodoc:
|
597
|
-
visitor.compile(node)
|
598
|
-
end
|
599
|
-
|
600
576
|
def default_index_type?(index) # :nodoc:
|
601
577
|
index.using.nil?
|
602
578
|
end
|
@@ -716,7 +692,6 @@ module ActiveRecord
|
|
716
692
|
binds: binds,
|
717
693
|
type_casted_binds: type_casted_binds,
|
718
694
|
statement_name: statement_name,
|
719
|
-
connection_id: object_id,
|
720
695
|
connection: self) do
|
721
696
|
@lock.synchronize do
|
722
697
|
yield
|
@@ -771,6 +746,14 @@ module ActiveRecord
|
|
771
746
|
|
772
747
|
def build_statement_pool
|
773
748
|
end
|
749
|
+
|
750
|
+
# Builds the result object.
|
751
|
+
#
|
752
|
+
# This is an internal hook to make possible connection adapters to build
|
753
|
+
# custom result objects with connection-specific data.
|
754
|
+
def build_result(columns:, rows:, column_types: {})
|
755
|
+
ActiveRecord::Result.new(columns, rows, column_types)
|
756
|
+
end
|
774
757
|
end
|
775
758
|
end
|
776
759
|
end
|
@@ -92,6 +92,14 @@ module ActiveRecord
|
|
92
92
|
true
|
93
93
|
end
|
94
94
|
|
95
|
+
def supports_check_constraints?
|
96
|
+
if mariadb?
|
97
|
+
database_version >= "10.2.1"
|
98
|
+
else
|
99
|
+
database_version >= "8.0.16"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
95
103
|
def supports_views?
|
96
104
|
true
|
97
105
|
end
|
@@ -104,7 +112,7 @@ module ActiveRecord
|
|
104
112
|
mariadb? || database_version >= "5.7.5"
|
105
113
|
end
|
106
114
|
|
107
|
-
# See https://dev.mysql.com/doc/refman/
|
115
|
+
# See https://dev.mysql.com/doc/refman/en/optimizer-hints.html for more details.
|
108
116
|
def supports_optimizer_hints?
|
109
117
|
!mariadb? && database_version >= "5.7.7"
|
110
118
|
end
|
@@ -142,7 +150,12 @@ module ActiveRecord
|
|
142
150
|
end
|
143
151
|
|
144
152
|
def index_algorithms
|
145
|
-
{
|
153
|
+
{
|
154
|
+
default: "ALGORITHM = DEFAULT",
|
155
|
+
copy: "ALGORITHM = COPY",
|
156
|
+
inplace: "ALGORITHM = INPLACE",
|
157
|
+
instant: "ALGORITHM = INSTANT",
|
158
|
+
}
|
146
159
|
end
|
147
160
|
|
148
161
|
# HELPER METHODS ===========================================
|
@@ -183,18 +196,10 @@ module ActiveRecord
|
|
183
196
|
# DATABASE STATEMENTS ======================================
|
184
197
|
#++
|
185
198
|
|
186
|
-
def explain(arel, binds = [])
|
187
|
-
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
188
|
-
start = Concurrent.monotonic_time
|
189
|
-
result = exec_query(sql, "EXPLAIN", binds)
|
190
|
-
elapsed = Concurrent.monotonic_time - start
|
191
|
-
|
192
|
-
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
193
|
-
end
|
194
|
-
|
195
199
|
# Executes the SQL statement in the context of this connection.
|
196
200
|
def execute(sql, name = nil)
|
197
201
|
materialize_transactions
|
202
|
+
mark_transaction_written_if_write(sql)
|
198
203
|
|
199
204
|
log(sql, name) do
|
200
205
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
@@ -211,7 +216,7 @@ module ActiveRecord
|
|
211
216
|
end
|
212
217
|
|
213
218
|
def begin_db_transaction
|
214
|
-
execute
|
219
|
+
execute("BEGIN", "TRANSACTION")
|
215
220
|
end
|
216
221
|
|
217
222
|
def begin_isolated_db_transaction(isolation)
|
@@ -220,11 +225,11 @@ module ActiveRecord
|
|
220
225
|
end
|
221
226
|
|
222
227
|
def commit_db_transaction #:nodoc:
|
223
|
-
execute
|
228
|
+
execute("COMMIT", "TRANSACTION")
|
224
229
|
end
|
225
230
|
|
226
231
|
def exec_rollback_db_transaction #:nodoc:
|
227
|
-
execute
|
232
|
+
execute("ROLLBACK", "TRANSACTION")
|
228
233
|
end
|
229
234
|
|
230
235
|
def empty_insert_statement_value(primary_key = nil)
|
@@ -305,6 +310,8 @@ module ActiveRecord
|
|
305
310
|
# Example:
|
306
311
|
# rename_table('octopuses', 'octopi')
|
307
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)
|
308
315
|
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
309
316
|
rename_table_indexes(table_name, new_name)
|
310
317
|
end
|
@@ -324,7 +331,8 @@ module ActiveRecord
|
|
324
331
|
# Although this command ignores most +options+ and the block if one is given,
|
325
332
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
326
333
|
# In that case, +options+ and the block will be used by create_table.
|
327
|
-
def drop_table(table_name, options
|
334
|
+
def drop_table(table_name, **options)
|
335
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
328
336
|
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
|
329
337
|
end
|
330
338
|
|
@@ -356,8 +364,8 @@ module ActiveRecord
|
|
356
364
|
change_column table_name, column_name, nil, comment: comment
|
357
365
|
end
|
358
366
|
|
359
|
-
def change_column(table_name, column_name, type, options
|
360
|
-
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)}")
|
361
369
|
end
|
362
370
|
|
363
371
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
@@ -365,10 +373,13 @@ module ActiveRecord
|
|
365
373
|
rename_column_indexes(table_name, column_name, new_column_name)
|
366
374
|
end
|
367
375
|
|
368
|
-
def add_index(table_name, column_name, options
|
369
|
-
|
370
|
-
|
371
|
-
|
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)
|
372
383
|
end
|
373
384
|
|
374
385
|
def add_sql_comment!(sql, comment) # :nodoc:
|
@@ -412,25 +423,60 @@ module ActiveRecord
|
|
412
423
|
end
|
413
424
|
end
|
414
425
|
|
415
|
-
def
|
416
|
-
|
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
|
417
453
|
|
454
|
+
def table_options(table_name) # :nodoc:
|
418
455
|
create_table_info = create_table_info(table_name)
|
419
456
|
|
420
457
|
# strip create_definitions and partition_options
|
421
458
|
# Be aware that `create_table_info` might not include any table options due to `NO_TABLE_OPTIONS` sql mode.
|
422
459
|
raw_table_options = create_table_info.sub(/\A.*\n\) ?/m, "").sub(/\n\/\*!.*\*\/\n\z/m, "").strip
|
423
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
|
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 unless raw_table_options.blank?
|
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
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
|
|
@@ -533,7 +565,10 @@ module ActiveRecord
|
|
533
565
|
def initialize_type_map(m = type_map)
|
534
566
|
super
|
535
567
|
|
536
|
-
|
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
|
537
572
|
|
538
573
|
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
539
574
|
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
@@ -553,20 +588,11 @@ module ActiveRecord
|
|
553
588
|
register_integer_type m, %r(^tinyint)i, limit: 1
|
554
589
|
|
555
590
|
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
|
556
|
-
m.alias_type %r(year)i,
|
557
|
-
m.alias_type %r(bit)i,
|
591
|
+
m.alias_type %r(year)i, "integer"
|
592
|
+
m.alias_type %r(bit)i, "binary"
|
558
593
|
|
559
|
-
m.register_type
|
560
|
-
|
561
|
-
.split(",").map { |enum| enum.strip.length - 2 }.max
|
562
|
-
MysqlString.new(limit: limit)
|
563
|
-
end
|
564
|
-
|
565
|
-
m.register_type(%r(^set)i) do |sql_type|
|
566
|
-
limit = sql_type[/^set\s*\((.+)\)/i, 1]
|
567
|
-
.split(",").map { |set| set.strip.length - 1 }.sum - 1
|
568
|
-
MysqlString.new(limit: limit)
|
569
|
-
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)
|
570
596
|
end
|
571
597
|
|
572
598
|
def register_integer_type(mapping, key, **options)
|
@@ -587,7 +613,8 @@ module ActiveRecord
|
|
587
613
|
end
|
588
614
|
end
|
589
615
|
|
590
|
-
# 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
|
591
618
|
ER_FILSORT_ABORT = 1028
|
592
619
|
ER_DUP_ENTRY = 1062
|
593
620
|
ER_NOT_NULL_VIOLATION = 1048
|
@@ -608,6 +635,14 @@ module ActiveRecord
|
|
608
635
|
|
609
636
|
def translate_exception(exception, message:, sql:, binds:)
|
610
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)
|
611
646
|
when ER_DUP_ENTRY
|
612
647
|
RecordNotUnique.new(message, sql: sql, binds: binds)
|
613
648
|
when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
|
@@ -639,7 +674,7 @@ module ActiveRecord
|
|
639
674
|
end
|
640
675
|
end
|
641
676
|
|
642
|
-
def change_column_for_alter(table_name, column_name, type, options
|
677
|
+
def change_column_for_alter(table_name, column_name, type, **options)
|
643
678
|
column = column_for(table_name, column_name)
|
644
679
|
type ||= column.sql_type
|
645
680
|
|
@@ -661,11 +696,14 @@ module ActiveRecord
|
|
661
696
|
end
|
662
697
|
|
663
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
|
+
|
664
701
|
column = column_for(table_name, column_name)
|
665
702
|
options = {
|
666
703
|
default: column.default,
|
667
704
|
null: column.null,
|
668
|
-
auto_increment: column.auto_increment
|
705
|
+
auto_increment: column.auto_increment?,
|
706
|
+
comment: column.comment
|
669
707
|
}
|
670
708
|
|
671
709
|
current_type = exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
|
@@ -674,19 +712,32 @@ module ActiveRecord
|
|
674
712
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
675
713
|
end
|
676
714
|
|
677
|
-
def add_index_for_alter(table_name, column_name, options
|
678
|
-
|
679
|
-
|
680
|
-
|
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}"
|
681
720
|
end
|
682
721
|
|
683
|
-
def remove_index_for_alter(table_name,
|
684
|
-
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)
|
685
724
|
"DROP INDEX #{quote_column_name(index_name)}"
|
686
725
|
end
|
687
726
|
|
688
727
|
def supports_rename_index?
|
689
|
-
mariadb?
|
728
|
+
if mariadb?
|
729
|
+
database_version >= "10.5.2"
|
730
|
+
else
|
731
|
+
database_version >= "5.7.6"
|
732
|
+
end
|
733
|
+
end
|
734
|
+
|
735
|
+
def supports_rename_column?
|
736
|
+
if mariadb?
|
737
|
+
database_version >= "10.5.2"
|
738
|
+
else
|
739
|
+
database_version >= "8.0.3"
|
740
|
+
end
|
690
741
|
end
|
691
742
|
|
692
743
|
def configure_connection
|
@@ -703,7 +754,7 @@ module ActiveRecord
|
|
703
754
|
defaults = [":default", :default].to_set
|
704
755
|
|
705
756
|
# Make MySQL reject illegal values rather than truncating or blanking them, see
|
706
|
-
# https://dev.mysql.com/doc/refman/
|
757
|
+
# https://dev.mysql.com/doc/refman/en/sql-mode.html#sqlmode_strict_all_tables
|
707
758
|
# If the user has provided another value for sql_mode, don't replace it.
|
708
759
|
if sql_mode = variables.delete("sql_mode")
|
709
760
|
sql_mode = quote(sql_mode)
|
@@ -720,7 +771,7 @@ module ActiveRecord
|
|
720
771
|
sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
|
721
772
|
|
722
773
|
# NAMES does not have an equals sign, see
|
723
|
-
# https://dev.mysql.com/doc/refman/
|
774
|
+
# https://dev.mysql.com/doc/refman/en/set-names.html
|
724
775
|
# (trailing comma because variable_assignments will always have content)
|
725
776
|
if @config[:encoding]
|
726
777
|
encoding = +"NAMES #{@config[:encoding]}"
|
@@ -739,7 +790,7 @@ module ActiveRecord
|
|
739
790
|
end.compact.join(", ")
|
740
791
|
|
741
792
|
# ...and send them all in one query
|
742
|
-
execute
|
793
|
+
execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
743
794
|
end
|
744
795
|
|
745
796
|
def column_definitions(table_name) # :nodoc:
|
@@ -788,26 +839,16 @@ module ActiveRecord
|
|
788
839
|
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
789
840
|
end
|
790
841
|
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
when true then "1"
|
795
|
-
when false then "0"
|
796
|
-
else super
|
797
|
-
end
|
798
|
-
end
|
842
|
+
# Alias MysqlString to work Mashal.load(File.read("legacy_record.dump")).
|
843
|
+
# TODO: Remove the constant alias once Rails 6.1 has released.
|
844
|
+
MysqlString = Type::String # :nodoc:
|
799
845
|
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
else super
|
806
|
-
end
|
807
|
-
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)
|
808
851
|
end
|
809
|
-
|
810
|
-
ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2)
|
811
852
|
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
|
812
853
|
end
|
813
854
|
end
|