activerecord 7.2.3 → 8.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +391 -958
- data/README.rdoc +1 -1
- data/lib/active_record/association_relation.rb +1 -0
- data/lib/active_record/associations/association.rb +34 -10
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/collection_association.rb +1 -1
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/preloader/association.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +34 -4
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/primary_key.rb +4 -8
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -12
- data/lib/active_record/autosave_association.rb +69 -27
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +34 -25
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +6 -15
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +34 -7
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +31 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +21 -40
- data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +50 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +84 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -8
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +72 -43
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +6 -12
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +59 -16
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +46 -96
- data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +80 -100
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +9 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +53 -12
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +0 -17
- data/lib/active_record/connection_adapters.rb +0 -56
- data/lib/active_record/connection_handling.rb +23 -1
- data/lib/active_record/core.rb +29 -14
- data/lib/active_record/database_configurations/database_config.rb +4 -0
- data/lib/active_record/database_configurations/hash_config.rb +16 -2
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +4 -4
- data/lib/active_record/encryption/encrypted_attribute_type.rb +10 -1
- data/lib/active_record/encryption/encryptor.rb +16 -8
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +8 -1
- data/lib/active_record/enum.rb +9 -22
- data/lib/active_record/errors.rb +13 -5
- data/lib/active_record/fixtures.rb +0 -2
- data/lib/active_record/future_result.rb +13 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/insert_all.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +5 -11
- data/lib/active_record/migration/command_recorder.rb +31 -11
- data/lib/active_record/migration/compatibility.rb +5 -2
- data/lib/active_record/migration.rb +38 -42
- data/lib/active_record/model_schema.rb +3 -4
- data/lib/active_record/nested_attributes.rb +4 -6
- data/lib/active_record/persistence.rb +128 -130
- data/lib/active_record/query_logs.rb +102 -50
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +8 -8
- data/lib/active_record/railtie.rb +2 -26
- data/lib/active_record/railties/databases.rake +11 -35
- data/lib/active_record/reflection.rb +18 -21
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +132 -72
- data/lib/active_record/relation/calculations.rb +40 -39
- data/lib/active_record/relation/delegation.rb +25 -14
- data/lib/active_record/relation/finder_methods.rb +18 -18
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +13 -0
- data/lib/active_record/relation/query_methods.rb +105 -61
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation.rb +79 -61
- data/lib/active_record/result.rb +66 -4
- data/lib/active_record/sanitization.rb +7 -6
- data/lib/active_record/schema_dumper.rb +5 -0
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/statement_cache.rb +14 -14
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/table_metadata.rb +1 -3
- data/lib/active_record/tasks/database_tasks.rb +69 -60
- data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
- data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +12 -0
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transactions.rb +5 -6
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +21 -48
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/node.rb +1 -1
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/table.rb +3 -7
- metadata +9 -10
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
|
@@ -448,10 +448,14 @@ module ActiveRecord
|
|
|
448
448
|
# = Active Record Real \Transaction
|
|
449
449
|
class RealTransaction < Transaction
|
|
450
450
|
def materialize!
|
|
451
|
-
if
|
|
452
|
-
|
|
451
|
+
if joinable?
|
|
452
|
+
if isolation_level
|
|
453
|
+
connection.begin_isolated_db_transaction(isolation_level)
|
|
454
|
+
else
|
|
455
|
+
connection.begin_db_transaction
|
|
456
|
+
end
|
|
453
457
|
else
|
|
454
|
-
connection.
|
|
458
|
+
connection.begin_deferred_transaction(isolation_level)
|
|
455
459
|
end
|
|
456
460
|
|
|
457
461
|
super
|
|
@@ -472,13 +476,19 @@ module ActiveRecord
|
|
|
472
476
|
end
|
|
473
477
|
|
|
474
478
|
def rollback
|
|
475
|
-
|
|
479
|
+
if materialized?
|
|
480
|
+
connection.rollback_db_transaction
|
|
481
|
+
connection.reset_isolation_level if isolation_level
|
|
482
|
+
end
|
|
476
483
|
@state.full_rollback!
|
|
477
484
|
@instrumenter.finish(:rollback) if materialized?
|
|
478
485
|
end
|
|
479
486
|
|
|
480
487
|
def commit
|
|
481
|
-
|
|
488
|
+
if materialized?
|
|
489
|
+
connection.commit_db_transaction
|
|
490
|
+
connection.reset_isolation_level if isolation_level
|
|
491
|
+
end
|
|
482
492
|
@state.full_commit!
|
|
483
493
|
@instrumenter.finish(:commit) if materialized?
|
|
484
494
|
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "set"
|
|
4
3
|
require "active_record/connection_adapters/sql_type_metadata"
|
|
5
4
|
require "active_record/connection_adapters/abstract/schema_dumper"
|
|
6
5
|
require "active_record/connection_adapters/abstract/schema_creation"
|
|
@@ -153,7 +152,6 @@ module ActiveRecord
|
|
|
153
152
|
|
|
154
153
|
@owner = nil
|
|
155
154
|
@pinned = false
|
|
156
|
-
@instrumenter = ActiveSupport::Notifications.instrumenter
|
|
157
155
|
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
|
158
156
|
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
159
157
|
@visitor = arel_visitor
|
|
@@ -194,19 +192,6 @@ module ActiveRecord
|
|
|
194
192
|
end
|
|
195
193
|
end
|
|
196
194
|
|
|
197
|
-
EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
|
|
198
|
-
EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze # :nodoc:
|
|
199
|
-
private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
|
|
200
|
-
def with_instrumenter(instrumenter, &block) # :nodoc:
|
|
201
|
-
Thread.handle_interrupt(EXCEPTION_NEVER) do
|
|
202
|
-
previous_instrumenter = @instrumenter
|
|
203
|
-
@instrumenter = instrumenter
|
|
204
|
-
Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
|
|
205
|
-
ensure
|
|
206
|
-
@instrumenter = previous_instrumenter
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
|
|
210
195
|
def check_if_write_query(sql) # :nodoc:
|
|
211
196
|
if preventing_writes? && write_query?(sql)
|
|
212
197
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
|
@@ -243,9 +228,9 @@ module ActiveRecord
|
|
|
243
228
|
# the value of +current_preventing_writes+.
|
|
244
229
|
def preventing_writes?
|
|
245
230
|
return true if replica?
|
|
246
|
-
return false if
|
|
231
|
+
return false if connection_descriptor.nil?
|
|
247
232
|
|
|
248
|
-
|
|
233
|
+
connection_descriptor.current_preventing_writes
|
|
249
234
|
end
|
|
250
235
|
|
|
251
236
|
def prepared_statements?
|
|
@@ -296,8 +281,8 @@ module ActiveRecord
|
|
|
296
281
|
@owner = ActiveSupport::IsolatedExecutionState.context
|
|
297
282
|
end
|
|
298
283
|
|
|
299
|
-
def
|
|
300
|
-
@pool.
|
|
284
|
+
def connection_descriptor # :nodoc:
|
|
285
|
+
@pool.connection_descriptor
|
|
301
286
|
end
|
|
302
287
|
|
|
303
288
|
# The role (e.g. +:writing+) for the current connection. In a
|
|
@@ -590,23 +575,31 @@ module ActiveRecord
|
|
|
590
575
|
end
|
|
591
576
|
|
|
592
577
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
593
|
-
def create_enum(
|
|
578
|
+
def create_enum(...) # :nodoc:
|
|
594
579
|
end
|
|
595
580
|
|
|
596
581
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
597
|
-
def drop_enum(
|
|
582
|
+
def drop_enum(...) # :nodoc:
|
|
598
583
|
end
|
|
599
584
|
|
|
600
585
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
601
|
-
def rename_enum(
|
|
586
|
+
def rename_enum(...) # :nodoc:
|
|
602
587
|
end
|
|
603
588
|
|
|
604
589
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
605
|
-
def add_enum_value(
|
|
590
|
+
def add_enum_value(...) # :nodoc:
|
|
606
591
|
end
|
|
607
592
|
|
|
608
593
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
609
|
-
def rename_enum_value(
|
|
594
|
+
def rename_enum_value(...) # :nodoc:
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
# This is meant to be implemented by the adapters that support virtual tables
|
|
598
|
+
def create_virtual_table(*) # :nodoc:
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
# This is meant to be implemented by the adapters that support virtual tables
|
|
602
|
+
def drop_virtual_table(*) # :nodoc:
|
|
610
603
|
end
|
|
611
604
|
|
|
612
605
|
def advisory_locks_enabled? # :nodoc:
|
|
@@ -1066,7 +1059,8 @@ module ActiveRecord
|
|
|
1066
1059
|
end
|
|
1067
1060
|
|
|
1068
1061
|
def retryable_connection_error?(exception)
|
|
1069
|
-
exception.is_a?(ConnectionNotEstablished)
|
|
1062
|
+
(exception.is_a?(ConnectionNotEstablished) && !exception.is_a?(ConnectionNotDefined)) ||
|
|
1063
|
+
exception.is_a?(ConnectionFailed)
|
|
1070
1064
|
end
|
|
1071
1065
|
|
|
1072
1066
|
def invalidate_transaction(exception)
|
|
@@ -1127,24 +1121,25 @@ module ActiveRecord
|
|
|
1127
1121
|
end
|
|
1128
1122
|
end
|
|
1129
1123
|
|
|
1130
|
-
def translate_exception_class(
|
|
1131
|
-
|
|
1124
|
+
def translate_exception_class(native_error, sql, binds)
|
|
1125
|
+
return native_error if native_error.is_a?(ActiveRecordError)
|
|
1126
|
+
|
|
1127
|
+
message = "#{native_error.class.name}: #{native_error.message}"
|
|
1132
1128
|
|
|
1133
|
-
|
|
1134
|
-
|
|
1129
|
+
active_record_error = translate_exception(
|
|
1130
|
+
native_error, message: message, sql: sql, binds: binds
|
|
1135
1131
|
)
|
|
1136
|
-
|
|
1137
|
-
|
|
1132
|
+
active_record_error.set_backtrace(native_error.backtrace)
|
|
1133
|
+
active_record_error
|
|
1138
1134
|
end
|
|
1139
1135
|
|
|
1140
|
-
def log(sql, name = "SQL", binds = [], type_casted_binds = [],
|
|
1141
|
-
|
|
1136
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], async: false, &block) # :doc:
|
|
1137
|
+
instrumenter.instrument(
|
|
1142
1138
|
"sql.active_record",
|
|
1143
1139
|
sql: sql,
|
|
1144
1140
|
name: name,
|
|
1145
1141
|
binds: binds,
|
|
1146
1142
|
type_casted_binds: type_casted_binds,
|
|
1147
|
-
statement_name: statement_name,
|
|
1148
1143
|
async: async,
|
|
1149
1144
|
connection: self,
|
|
1150
1145
|
transaction: current_transaction.user_transaction.presence,
|
|
@@ -1155,11 +1150,8 @@ module ActiveRecord
|
|
|
1155
1150
|
raise ex.set_query(sql, binds)
|
|
1156
1151
|
end
|
|
1157
1152
|
|
|
1158
|
-
def
|
|
1159
|
-
|
|
1160
|
-
sql = transformer.call(sql, self)
|
|
1161
|
-
end
|
|
1162
|
-
sql
|
|
1153
|
+
def instrumenter # :nodoc:
|
|
1154
|
+
ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] ||= ActiveSupport::Notifications.instrumenter
|
|
1163
1155
|
end
|
|
1164
1156
|
|
|
1165
1157
|
def translate_exception(exception, message:, sql:, binds:)
|
|
@@ -1172,10 +1164,6 @@ module ActiveRecord
|
|
|
1172
1164
|
end
|
|
1173
1165
|
end
|
|
1174
1166
|
|
|
1175
|
-
def without_prepared_statement?(binds)
|
|
1176
|
-
!prepared_statements || binds.empty?
|
|
1177
|
-
end
|
|
1178
|
-
|
|
1179
1167
|
def column_for(table_name, column_name)
|
|
1180
1168
|
column_name = column_name.to_s
|
|
1181
1169
|
columns(table_name).detect { |c| c.name == column_name } ||
|
|
@@ -79,7 +79,7 @@ module ActiveRecord
|
|
|
79
79
|
|
|
80
80
|
args << config.database
|
|
81
81
|
|
|
82
|
-
find_cmd_and_exec([
|
|
82
|
+
find_cmd_and_exec(ActiveRecord.database_cli[:mysql], *args)
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
|
|
@@ -98,7 +98,7 @@ module ActiveRecord
|
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
def supports_index_sort_order?
|
|
101
|
-
|
|
101
|
+
mariadb? ? database_version >= "10.8.1" : database_version >= "8.0.1"
|
|
102
102
|
end
|
|
103
103
|
|
|
104
104
|
def supports_expression_index?
|
|
@@ -138,7 +138,7 @@ module ActiveRecord
|
|
|
138
138
|
end
|
|
139
139
|
|
|
140
140
|
def supports_datetime_with_precision?
|
|
141
|
-
|
|
141
|
+
true
|
|
142
142
|
end
|
|
143
143
|
|
|
144
144
|
def supports_virtual_columns?
|
|
@@ -201,12 +201,6 @@ module ActiveRecord
|
|
|
201
201
|
|
|
202
202
|
# HELPER METHODS ===========================================
|
|
203
203
|
|
|
204
|
-
# The two drivers have slightly different ways of yielding hashes of results, so
|
|
205
|
-
# this method must be implemented to provide a uniform interface.
|
|
206
|
-
def each_hash(result) # :nodoc:
|
|
207
|
-
raise NotImplementedError
|
|
208
|
-
end
|
|
209
|
-
|
|
210
204
|
# Must return the MySQL error number from the exception, if the exception has an
|
|
211
205
|
# error number.
|
|
212
206
|
def error_number(exception) # :nodoc:
|
|
@@ -230,24 +224,19 @@ module ActiveRecord
|
|
|
230
224
|
# DATABASE STATEMENTS ======================================
|
|
231
225
|
#++
|
|
232
226
|
|
|
233
|
-
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
|
234
|
-
# to write stuff in an abstract way without concerning ourselves about whether it
|
|
235
|
-
# needs to be explicitly freed or not.
|
|
236
|
-
def execute_and_free(sql, name = nil, async: false, allow_retry: false) # :nodoc:
|
|
237
|
-
sql = transform_query(sql)
|
|
238
|
-
check_if_write_query(sql)
|
|
239
|
-
|
|
240
|
-
mark_transaction_written_if_write(sql)
|
|
241
|
-
yield raw_execute(sql, name, async: async, allow_retry: allow_retry)
|
|
242
|
-
end
|
|
243
|
-
|
|
244
227
|
def begin_db_transaction # :nodoc:
|
|
245
228
|
internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
246
229
|
end
|
|
247
230
|
|
|
248
231
|
def begin_isolated_db_transaction(isolation) # :nodoc:
|
|
249
|
-
|
|
250
|
-
|
|
232
|
+
# From MySQL manual: The [SET TRANSACTION] statement applies only to the next single transaction performed within the session.
|
|
233
|
+
# So we don't need to implement #reset_isolation_level
|
|
234
|
+
execute_batch(
|
|
235
|
+
["SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "BEGIN"],
|
|
236
|
+
"TRANSACTION",
|
|
237
|
+
allow_retry: true,
|
|
238
|
+
materialize_transactions: false,
|
|
239
|
+
)
|
|
251
240
|
end
|
|
252
241
|
|
|
253
242
|
def commit_db_transaction # :nodoc:
|
|
@@ -347,7 +336,7 @@ module ActiveRecord
|
|
|
347
336
|
rename_table_indexes(table_name, new_name, **options)
|
|
348
337
|
end
|
|
349
338
|
|
|
350
|
-
# Drops a table from the database.
|
|
339
|
+
# Drops a table or tables from the database.
|
|
351
340
|
#
|
|
352
341
|
# [<tt>:force</tt>]
|
|
353
342
|
# Set to +:cascade+ to drop dependent objects as well.
|
|
@@ -361,10 +350,10 @@ module ActiveRecord
|
|
|
361
350
|
#
|
|
362
351
|
# Although this command ignores most +options+ and the block if one is given,
|
|
363
352
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
|
364
|
-
# In that case, +options+ and the block will be used by create_table.
|
|
365
|
-
def drop_table(
|
|
366
|
-
schema_cache.clear_data_source_cache!(table_name.to_s)
|
|
367
|
-
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
|
|
353
|
+
# In that case, +options+ and the block will be used by #create_table except if you provide more than one table which is not supported.
|
|
354
|
+
def drop_table(*table_names, **options)
|
|
355
|
+
table_names.each { |table_name| schema_cache.clear_data_source_cache!(table_name.to_s) }
|
|
356
|
+
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{table_names.map { |table_name| quote_table_name(table_name) }.join(', ')}#{' CASCADE' if options[:force] == :cascade}"
|
|
368
357
|
end
|
|
369
358
|
|
|
370
359
|
def rename_index(table_name, old_name, new_name)
|
|
@@ -588,7 +577,7 @@ module ActiveRecord
|
|
|
588
577
|
|
|
589
578
|
# SHOW VARIABLES LIKE 'name'
|
|
590
579
|
def show_variable(name)
|
|
591
|
-
query_value("SELECT @@#{name}", "SCHEMA")
|
|
580
|
+
query_value("SELECT @@#{name}", "SCHEMA", materialize_transactions: false, allow_retry: true)
|
|
592
581
|
rescue ActiveRecord::StatementInvalid
|
|
593
582
|
nil
|
|
594
583
|
end
|
|
@@ -693,8 +682,8 @@ module ActiveRecord
|
|
|
693
682
|
end
|
|
694
683
|
|
|
695
684
|
def check_version # :nodoc:
|
|
696
|
-
if database_version < "5.
|
|
697
|
-
raise DatabaseVersionError, "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.
|
|
685
|
+
if database_version < "5.6.4"
|
|
686
|
+
raise DatabaseVersionError, "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.6.4."
|
|
698
687
|
end
|
|
699
688
|
end
|
|
700
689
|
|
|
@@ -781,7 +770,6 @@ module ActiveRecord
|
|
|
781
770
|
def handle_warnings(sql)
|
|
782
771
|
return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
|
|
783
772
|
|
|
784
|
-
@affected_rows_before_warnings = @raw_connection.affected_rows
|
|
785
773
|
warning_count = @raw_connection.warning_count
|
|
786
774
|
result = @raw_connection.query("SHOW WARNINGS")
|
|
787
775
|
result = [
|
|
@@ -799,11 +787,6 @@ module ActiveRecord
|
|
|
799
787
|
warning.level == "Note" || super
|
|
800
788
|
end
|
|
801
789
|
|
|
802
|
-
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
|
803
|
-
# made since we established the connection
|
|
804
|
-
def sync_timezone_changes(raw_connection)
|
|
805
|
-
end
|
|
806
|
-
|
|
807
790
|
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
|
|
808
791
|
ER_DB_CREATE_EXISTS = 1007
|
|
809
792
|
ER_FILSORT_ABORT = 1028
|
|
@@ -973,13 +956,11 @@ module ActiveRecord
|
|
|
973
956
|
end.join(", ")
|
|
974
957
|
|
|
975
958
|
# ...and send them all in one query
|
|
976
|
-
|
|
959
|
+
raw_execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
|
977
960
|
end
|
|
978
961
|
|
|
979
962
|
def column_definitions(table_name) # :nodoc:
|
|
980
|
-
|
|
981
|
-
each_hash(result)
|
|
982
|
-
end
|
|
963
|
+
internal_exec_query("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", "SCHEMA")
|
|
983
964
|
end
|
|
984
965
|
|
|
985
966
|
def create_table_info(table_name) # :nodoc:
|
|
@@ -42,18 +42,12 @@ module ActiveRecord
|
|
|
42
42
|
# :method: unsigned_bigint
|
|
43
43
|
# :call-seq: unsigned_bigint(*names, **options)
|
|
44
44
|
|
|
45
|
-
##
|
|
46
|
-
# :method: unsigned_float
|
|
47
|
-
# :call-seq: unsigned_float(*names, **options)
|
|
48
|
-
|
|
49
|
-
##
|
|
50
|
-
# :method: unsigned_decimal
|
|
51
|
-
# :call-seq: unsigned_decimal(*names, **options)
|
|
52
|
-
|
|
53
45
|
included do
|
|
54
46
|
define_column_methods :blob, :tinyblob, :mediumblob, :longblob,
|
|
55
47
|
:tinytext, :mediumtext, :longtext, :unsigned_integer, :unsigned_bigint,
|
|
56
48
|
:unsigned_float, :unsigned_decimal
|
|
49
|
+
|
|
50
|
+
deprecate :unsigned_float, :unsigned_decimal, deprecator: ActiveRecord.deprecator
|
|
57
51
|
end
|
|
58
52
|
end
|
|
59
53
|
|
|
@@ -8,45 +8,43 @@ module ActiveRecord
|
|
|
8
8
|
def indexes(table_name)
|
|
9
9
|
indexes = []
|
|
10
10
|
current_index = nil
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
index_using = mysql_index_type
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
indexes << [
|
|
26
|
-
row[:Table],
|
|
27
|
-
row[:Key_name],
|
|
28
|
-
row[:Non_unique].to_i == 0,
|
|
29
|
-
[],
|
|
30
|
-
lengths: {},
|
|
31
|
-
orders: {},
|
|
32
|
-
type: index_type,
|
|
33
|
-
using: index_using,
|
|
34
|
-
comment: row[:Index_comment].presence
|
|
35
|
-
]
|
|
11
|
+
internal_exec_query("SHOW KEYS FROM #{quote_table_name(table_name)}", "SCHEMA").each do |row|
|
|
12
|
+
if current_index != row["Key_name"]
|
|
13
|
+
next if row["Key_name"] == "PRIMARY" # skip the primary key
|
|
14
|
+
current_index = row["Key_name"]
|
|
15
|
+
|
|
16
|
+
mysql_index_type = row["Index_type"].downcase.to_sym
|
|
17
|
+
case mysql_index_type
|
|
18
|
+
when :fulltext, :spatial
|
|
19
|
+
index_type = mysql_index_type
|
|
20
|
+
when :btree, :hash
|
|
21
|
+
index_using = mysql_index_type
|
|
36
22
|
end
|
|
37
23
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
24
|
+
indexes << [
|
|
25
|
+
row["Table"],
|
|
26
|
+
row["Key_name"],
|
|
27
|
+
row["Non_unique"].to_i == 0,
|
|
28
|
+
[],
|
|
29
|
+
lengths: {},
|
|
30
|
+
orders: {},
|
|
31
|
+
type: index_type,
|
|
32
|
+
using: index_using,
|
|
33
|
+
comment: row["Index_comment"].presence
|
|
34
|
+
]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
if expression = row["Expression"]
|
|
38
|
+
expression = expression.gsub("\\'", "'")
|
|
39
|
+
expression = +"(#{expression})" unless expression.start_with?("(")
|
|
40
|
+
indexes.last[-2] << expression
|
|
41
|
+
indexes.last[-1][:expressions] ||= {}
|
|
42
|
+
indexes.last[-1][:expressions][expression] = expression
|
|
43
|
+
indexes.last[-1][:orders][expression] = :desc if row["Collation"] == "D"
|
|
44
|
+
else
|
|
45
|
+
indexes.last[-2] << row["Column_name"]
|
|
46
|
+
indexes.last[-1][:lengths][row["Column_name"]] = row["Sub_part"].to_i if row["Sub_part"]
|
|
47
|
+
indexes.last[-1][:orders][row["Column_name"]] = :desc if row["Collation"] == "D"
|
|
50
48
|
end
|
|
51
49
|
end
|
|
52
50
|
|
|
@@ -87,6 +85,13 @@ module ActiveRecord
|
|
|
87
85
|
super
|
|
88
86
|
end
|
|
89
87
|
|
|
88
|
+
def remove_foreign_key(from_table, to_table = nil, **options)
|
|
89
|
+
# RESTRICT is by default in MySQL.
|
|
90
|
+
options.delete(:on_update) if options[:on_update] == :restrict
|
|
91
|
+
options.delete(:on_delete) if options[:on_delete] == :restrict
|
|
92
|
+
super
|
|
93
|
+
end
|
|
94
|
+
|
|
90
95
|
def internal_string_options_for_primary_key
|
|
91
96
|
super.tap do |options|
|
|
92
97
|
if !row_format_dynamic_by_default? && CHARSETS_OF_4BYTES_MAXLEN.include?(charset)
|
|
@@ -182,12 +187,12 @@ module ActiveRecord
|
|
|
182
187
|
end
|
|
183
188
|
|
|
184
189
|
def new_column_from_field(table_name, field, _definitions)
|
|
185
|
-
field_name = field.fetch(
|
|
186
|
-
type_metadata = fetch_type_metadata(field[
|
|
187
|
-
default, default_function = field[
|
|
190
|
+
field_name = field.fetch("Field")
|
|
191
|
+
type_metadata = fetch_type_metadata(field["Type"], field["Extra"])
|
|
192
|
+
default, default_function = field["Default"], nil
|
|
188
193
|
|
|
189
194
|
if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
|
|
190
|
-
default = "#{default} ON UPDATE #{default}" if /on update CURRENT_TIMESTAMP/i.match?(field[
|
|
195
|
+
default = "#{default} ON UPDATE #{default}" if /on update CURRENT_TIMESTAMP/i.match?(field["Extra"])
|
|
191
196
|
default, default_function = nil, default
|
|
192
197
|
elsif type_metadata.extra == "DEFAULT_GENERATED"
|
|
193
198
|
default = +"(#{default})" unless default.start_with?("(")
|
|
@@ -203,13 +208,13 @@ module ActiveRecord
|
|
|
203
208
|
end
|
|
204
209
|
|
|
205
210
|
MySQL::Column.new(
|
|
206
|
-
field[
|
|
211
|
+
field["Field"],
|
|
207
212
|
default,
|
|
208
213
|
type_metadata,
|
|
209
|
-
field[
|
|
214
|
+
field["Null"] == "YES",
|
|
210
215
|
default_function,
|
|
211
|
-
collation: field[
|
|
212
|
-
comment: field[
|
|
216
|
+
collation: field["Collation"],
|
|
217
|
+
comment: field["Comment"].presence
|
|
213
218
|
)
|
|
214
219
|
end
|
|
215
220
|
|