activerecord 6.0.3.5 → 6.1.0.rc1
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 +774 -735
- 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 +40 -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 -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 +52 -48
- 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 +4 -4
- 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 +27 -7
- data/lib/active_record/autosave_association.rb +57 -40
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +32 -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 +186 -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 +66 -24
- data/lib/active_record/connection_adapters/abstract_adapter.rb +36 -69
- 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 +33 -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 +2 -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/money.rb +2 -2
- 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 +220 -55
- 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 +27 -10
- 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 +33 -6
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +15 -4
- 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 +88 -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 +253 -98
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +70 -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 +2 -2
- 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 +6 -5
- 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 +0 -4
- 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 +36 -52
- 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
|
@@ -289,6 +321,16 @@ module ActiveRecord
|
|
289
321
|
if Thread.current.status == "aborting"
|
290
322
|
rollback_transaction
|
291
323
|
else
|
324
|
+
if !completed && transaction.written
|
325
|
+
ActiveSupport::Deprecation.warn(<<~EOW)
|
326
|
+
Using `return`, `break` or `throw` to exit a transaction block is
|
327
|
+
deprecated without replacement. If the `throw` came from
|
328
|
+
`Timeout.timeout(duration)`, pass an exception class as a second
|
329
|
+
argument so it doesn't use `throw` to abort its block. This results
|
330
|
+
in the transaction being committed, but in the next release of Rails
|
331
|
+
it will rollback.
|
332
|
+
EOW
|
333
|
+
end
|
292
334
|
begin
|
293
335
|
commit_transaction
|
294
336
|
rescue Exception
|
@@ -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,20 @@ 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
116
|
# Returns true if the connection is a replica, or if +prevent_writes+
|
152
117
|
# is set to true.
|
153
118
|
def preventing_writes?
|
154
|
-
|
119
|
+
if ActiveRecord::Base.legacy_connection_handling
|
120
|
+
replica? || ActiveRecord::Base.connection_handler.prevent_writes
|
121
|
+
else
|
122
|
+
replica? || ActiveRecord::Base.current_preventing_writes
|
123
|
+
end
|
155
124
|
end
|
156
125
|
|
157
126
|
def migrations_paths # :nodoc:
|
@@ -165,12 +134,15 @@ module ActiveRecord
|
|
165
134
|
def schema_migration # :nodoc:
|
166
135
|
@schema_migration ||= begin
|
167
136
|
conn = self
|
168
|
-
spec_name = conn.pool.
|
169
|
-
|
137
|
+
spec_name = conn.pool.pool_config.connection_specification_name
|
138
|
+
|
139
|
+
return ActiveRecord::SchemaMigration if spec_name == "ActiveRecord::Base"
|
140
|
+
|
141
|
+
schema_migration_name = "#{spec_name}::SchemaMigration"
|
170
142
|
|
171
143
|
Class.new(ActiveRecord::SchemaMigration) do
|
172
|
-
define_singleton_method(:name) {
|
173
|
-
define_singleton_method(:to_s) {
|
144
|
+
define_singleton_method(:name) { schema_migration_name }
|
145
|
+
define_singleton_method(:to_s) { schema_migration_name }
|
174
146
|
|
175
147
|
self.connection_specification_name = spec_name
|
176
148
|
end
|
@@ -363,12 +335,10 @@ module ActiveRecord
|
|
363
335
|
false
|
364
336
|
end
|
365
337
|
|
366
|
-
# Does this adapter support creating
|
367
|
-
|
368
|
-
|
369
|
-
supports_foreign_keys?
|
338
|
+
# Does this adapter support creating check constraints?
|
339
|
+
def supports_check_constraints?
|
340
|
+
false
|
370
341
|
end
|
371
|
-
deprecate :supports_foreign_keys_in_create?
|
372
342
|
|
373
343
|
# Does this adapter support views?
|
374
344
|
def supports_views?
|
@@ -400,12 +370,6 @@ module ActiveRecord
|
|
400
370
|
false
|
401
371
|
end
|
402
372
|
|
403
|
-
# Does this adapter support multi-value insert?
|
404
|
-
def supports_multi_insert?
|
405
|
-
true
|
406
|
-
end
|
407
|
-
deprecate :supports_multi_insert?
|
408
|
-
|
409
373
|
# Does this adapter support virtual columns?
|
410
374
|
def supports_virtual_columns?
|
411
375
|
false
|
@@ -565,7 +529,7 @@ module ActiveRecord
|
|
565
529
|
@connection
|
566
530
|
end
|
567
531
|
|
568
|
-
def default_uniqueness_comparison(attribute, value
|
532
|
+
def default_uniqueness_comparison(attribute, value) # :nodoc:
|
569
533
|
attribute.eq(value)
|
570
534
|
end
|
571
535
|
|
@@ -593,10 +557,6 @@ module ActiveRecord
|
|
593
557
|
pool.checkin self
|
594
558
|
end
|
595
559
|
|
596
|
-
def column_name_for_operation(operation, node) # :nodoc:
|
597
|
-
visitor.compile(node)
|
598
|
-
end
|
599
|
-
|
600
560
|
def default_index_type?(index) # :nodoc:
|
601
561
|
index.using.nil?
|
602
562
|
end
|
@@ -716,7 +676,6 @@ module ActiveRecord
|
|
716
676
|
binds: binds,
|
717
677
|
type_casted_binds: type_casted_binds,
|
718
678
|
statement_name: statement_name,
|
719
|
-
connection_id: object_id,
|
720
679
|
connection: self) do
|
721
680
|
@lock.synchronize do
|
722
681
|
yield
|
@@ -771,6 +730,14 @@ module ActiveRecord
|
|
771
730
|
|
772
731
|
def build_statement_pool
|
773
732
|
end
|
733
|
+
|
734
|
+
# Builds the result object.
|
735
|
+
#
|
736
|
+
# This is an internal hook to make possible connection adapters to build
|
737
|
+
# custom result objects with connection-specific data.
|
738
|
+
def build_result(columns:, rows:, column_types: {})
|
739
|
+
ActiveRecord::Result.new(columns, rows, column_types)
|
740
|
+
end
|
774
741
|
end
|
775
742
|
end
|
776
743
|
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
|