activerecord 7.2.3 → 8.0.0.beta1
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.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +192 -1261
- data/README.rdoc +2 -2
- data/lib/active_record/associations/alias_tracker.rb +4 -6
- data/lib/active_record/associations/association.rb +25 -5
- data/lib/active_record/associations/belongs_to_association.rb +2 -18
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/collection_association.rb +4 -4
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +4 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
- 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 +50 -32
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods.rb +19 -24
- data/lib/active_record/attributes.rb +26 -37
- data/lib/active_record/autosave_association.rb +81 -49
- data/lib/active_record/base.rb +2 -2
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +16 -10
- 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 +31 -75
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +14 -19
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -6
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +27 -9
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +27 -57
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +28 -58
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -15
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +42 -98
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -16
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -42
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +12 -14
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +51 -9
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +44 -101
- data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +76 -100
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -13
- 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 +8 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +60 -22
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -18
- data/lib/active_record/connection_handling.rb +29 -11
- data/lib/active_record/core.rb +15 -60
- data/lib/active_record/counter_cache.rb +1 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -3
- data/lib/active_record/delegated_type.rb +18 -18
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +5 -5
- data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
- data/lib/active_record/encryption/encryptor.rb +35 -29
- 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 +12 -13
- data/lib/active_record/errors.rb +16 -8
- data/lib/active_record/fixture_set/table_row.rb +2 -19
- data/lib/active_record/fixtures.rb +0 -1
- data/lib/active_record/future_result.rb +14 -10
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/insert_all.rb +1 -1
- data/lib/active_record/marshalling.rb +1 -4
- data/lib/active_record/migration/command_recorder.rb +22 -5
- data/lib/active_record/migration/compatibility.rb +5 -2
- data/lib/active_record/migration.rb +36 -35
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/nested_attributes.rb +4 -6
- data/lib/active_record/persistence.rb +128 -130
- data/lib/active_record/query_cache.rb +5 -4
- data/lib/active_record/query_logs.rb +98 -44
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +10 -10
- data/lib/active_record/railtie.rb +5 -6
- data/lib/active_record/railties/databases.rake +1 -2
- data/lib/active_record/reflection.rb +9 -7
- 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 +55 -55
- data/lib/active_record/relation/delegation.rb +25 -14
- data/lib/active_record/relation/finder_methods.rb +31 -32
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +0 -2
- 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 +5 -0
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +90 -91
- data/lib/active_record/relation/record_fetch_warning.rb +2 -2
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +2 -8
- data/lib/active_record/relation.rb +77 -76
- data/lib/active_record/result.rb +68 -7
- data/lib/active_record/sanitization.rb +7 -6
- data/lib/active_record/schema_dumper.rb +16 -29
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +6 -7
- data/lib/active_record/statement_cache.rb +12 -12
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +24 -15
- data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
- data/lib/active_record/tasks/postgresql_database_tasks.rb +0 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
- data/lib/active_record/test_fixtures.rb +12 -0
- data/lib/active_record/testing/query_assertions.rb +2 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transactions.rb +1 -3
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +16 -1
- data/lib/arel/collectors/bind.rb +1 -1
- data/lib/arel/crud.rb +0 -2
- data/lib/arel/delete_manager.rb +0 -5
- data/lib/arel/nodes/delete_statement.rb +2 -4
- data/lib/arel/nodes/update_statement.rb +2 -4
- data/lib/arel/select_manager.rb +2 -6
- data/lib/arel/update_manager.rb +0 -5
- data/lib/arel/visitors/dot.rb +0 -2
- data/lib/arel/visitors/sqlite.rb +0 -25
- data/lib/arel/visitors/to_sql.rb +1 -3
- metadata +14 -11
|
@@ -43,7 +43,6 @@ module ActiveRecord
|
|
|
43
43
|
|
|
44
44
|
attr_reader :pool
|
|
45
45
|
attr_reader :visitor, :owner, :logger, :lock
|
|
46
|
-
attr_accessor :pinned # :nodoc:
|
|
47
46
|
alias :in_use? :owner
|
|
48
47
|
|
|
49
48
|
def pool=(value)
|
|
@@ -152,7 +151,6 @@ module ActiveRecord
|
|
|
152
151
|
end
|
|
153
152
|
|
|
154
153
|
@owner = nil
|
|
155
|
-
@pinned = false
|
|
156
154
|
@instrumenter = ActiveSupport::Notifications.instrumenter
|
|
157
155
|
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
|
158
156
|
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
@@ -171,7 +169,6 @@ module ActiveRecord
|
|
|
171
169
|
@default_timezone = self.class.validate_default_timezone(@config[:default_timezone])
|
|
172
170
|
|
|
173
171
|
@raw_connection_dirty = false
|
|
174
|
-
@last_activity = nil
|
|
175
172
|
@verified = false
|
|
176
173
|
end
|
|
177
174
|
|
|
@@ -221,10 +218,6 @@ module ActiveRecord
|
|
|
221
218
|
(@config[:connection_retries] || 1).to_i
|
|
222
219
|
end
|
|
223
220
|
|
|
224
|
-
def verify_timeout
|
|
225
|
-
(@config[:verify_timeout] || 2).to_i
|
|
226
|
-
end
|
|
227
|
-
|
|
228
221
|
def retry_deadline
|
|
229
222
|
if @config[:retry_deadline]
|
|
230
223
|
@config[:retry_deadline].to_f
|
|
@@ -351,13 +344,6 @@ module ActiveRecord
|
|
|
351
344
|
Process.clock_gettime(Process::CLOCK_MONOTONIC) - @idle_since
|
|
352
345
|
end
|
|
353
346
|
|
|
354
|
-
# Seconds since this connection last communicated with the server
|
|
355
|
-
def seconds_since_last_activity # :nodoc:
|
|
356
|
-
if @raw_connection && @last_activity
|
|
357
|
-
Process.clock_gettime(Process::CLOCK_MONOTONIC) - @last_activity
|
|
358
|
-
end
|
|
359
|
-
end
|
|
360
|
-
|
|
361
347
|
def unprepared_statement
|
|
362
348
|
cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements
|
|
363
349
|
yield
|
|
@@ -590,23 +576,31 @@ module ActiveRecord
|
|
|
590
576
|
end
|
|
591
577
|
|
|
592
578
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
593
|
-
def create_enum(
|
|
579
|
+
def create_enum(...) # :nodoc:
|
|
594
580
|
end
|
|
595
581
|
|
|
596
582
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
597
|
-
def drop_enum(
|
|
583
|
+
def drop_enum(...) # :nodoc:
|
|
598
584
|
end
|
|
599
585
|
|
|
600
586
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
601
|
-
def rename_enum(
|
|
587
|
+
def rename_enum(...) # :nodoc:
|
|
602
588
|
end
|
|
603
589
|
|
|
604
590
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
605
|
-
def add_enum_value(
|
|
591
|
+
def add_enum_value(...) # :nodoc:
|
|
606
592
|
end
|
|
607
593
|
|
|
608
594
|
# This is meant to be implemented by the adapters that support custom enum types
|
|
609
|
-
def rename_enum_value(
|
|
595
|
+
def rename_enum_value(...) # :nodoc:
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
# This is meant to be implemented by the adapters that support virtual tables
|
|
599
|
+
def create_virtual_table(*) # :nodoc:
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
# This is meant to be implemented by the adapters that support virtual tables
|
|
603
|
+
def drop_virtual_table(*) # :nodoc:
|
|
610
604
|
end
|
|
611
605
|
|
|
612
606
|
def advisory_locks_enabled? # :nodoc:
|
|
@@ -677,12 +671,11 @@ module ActiveRecord
|
|
|
677
671
|
|
|
678
672
|
enable_lazy_transactions!
|
|
679
673
|
@raw_connection_dirty = false
|
|
680
|
-
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
681
674
|
@verified = true
|
|
682
675
|
|
|
683
676
|
reset_transaction(restore: restore_transactions) do
|
|
684
677
|
clear_cache!(new_connection: true)
|
|
685
|
-
|
|
678
|
+
configure_connection
|
|
686
679
|
end
|
|
687
680
|
rescue => original_exception
|
|
688
681
|
translated_exception = translate_exception_class(original_exception, nil, nil)
|
|
@@ -697,7 +690,6 @@ module ActiveRecord
|
|
|
697
690
|
end
|
|
698
691
|
end
|
|
699
692
|
|
|
700
|
-
@last_activity = nil
|
|
701
693
|
@verified = false
|
|
702
694
|
|
|
703
695
|
raise translated_exception
|
|
@@ -735,7 +727,7 @@ module ActiveRecord
|
|
|
735
727
|
def reset!
|
|
736
728
|
clear_cache!(new_connection: true)
|
|
737
729
|
reset_transaction
|
|
738
|
-
|
|
730
|
+
configure_connection
|
|
739
731
|
end
|
|
740
732
|
|
|
741
733
|
# Removes the connection from the pool and disconnect it.
|
|
@@ -771,8 +763,7 @@ module ActiveRecord
|
|
|
771
763
|
if @unconfigured_connection
|
|
772
764
|
@raw_connection = @unconfigured_connection
|
|
773
765
|
@unconfigured_connection = nil
|
|
774
|
-
|
|
775
|
-
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
766
|
+
configure_connection
|
|
776
767
|
@verified = true
|
|
777
768
|
return
|
|
778
769
|
end
|
|
@@ -1002,9 +993,6 @@ module ActiveRecord
|
|
|
1002
993
|
if @verified
|
|
1003
994
|
# Cool, we're confident the connection's ready to use. (Note this might have
|
|
1004
995
|
# become true during the above #materialize_transactions.)
|
|
1005
|
-
elsif (last_activity = seconds_since_last_activity) && last_activity < verify_timeout
|
|
1006
|
-
# We haven't actually verified the connection since we acquired it, but it
|
|
1007
|
-
# has been used very recently. We're going to assume it's still okay.
|
|
1008
996
|
elsif reconnectable
|
|
1009
997
|
if allow_retry
|
|
1010
998
|
# Not sure about the connection yet, but if anything goes wrong we can
|
|
@@ -1046,7 +1034,6 @@ module ActiveRecord
|
|
|
1046
1034
|
# Barring a known-retryable error inside the query (regardless of
|
|
1047
1035
|
# whether we were in a _position_ to retry it), we should infer that
|
|
1048
1036
|
# there's likely a real problem with the connection.
|
|
1049
|
-
@last_activity = nil
|
|
1050
1037
|
@verified = false
|
|
1051
1038
|
end
|
|
1052
1039
|
|
|
@@ -1061,12 +1048,12 @@ module ActiveRecord
|
|
|
1061
1048
|
# `with_raw_connection` block only when the block is guaranteed to
|
|
1062
1049
|
# exercise the raw connection.
|
|
1063
1050
|
def verified!
|
|
1064
|
-
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
1065
1051
|
@verified = true
|
|
1066
1052
|
end
|
|
1067
1053
|
|
|
1068
1054
|
def retryable_connection_error?(exception)
|
|
1069
|
-
exception.is_a?(ConnectionNotEstablished)
|
|
1055
|
+
(exception.is_a?(ConnectionNotEstablished) && !exception.is_a?(ConnectionNotDefined)) ||
|
|
1056
|
+
exception.is_a?(ConnectionFailed)
|
|
1070
1057
|
end
|
|
1071
1058
|
|
|
1072
1059
|
def invalidate_transaction(exception)
|
|
@@ -1127,24 +1114,25 @@ module ActiveRecord
|
|
|
1127
1114
|
end
|
|
1128
1115
|
end
|
|
1129
1116
|
|
|
1130
|
-
def translate_exception_class(
|
|
1131
|
-
|
|
1117
|
+
def translate_exception_class(native_error, sql, binds)
|
|
1118
|
+
return native_error if native_error.is_a?(ActiveRecordError)
|
|
1132
1119
|
|
|
1133
|
-
|
|
1134
|
-
|
|
1120
|
+
message = "#{native_error.class.name}: #{native_error.message}"
|
|
1121
|
+
|
|
1122
|
+
active_record_error = translate_exception(
|
|
1123
|
+
native_error, message: message, sql: sql, binds: binds
|
|
1135
1124
|
)
|
|
1136
|
-
|
|
1137
|
-
|
|
1125
|
+
active_record_error.set_backtrace(native_error.backtrace)
|
|
1126
|
+
active_record_error
|
|
1138
1127
|
end
|
|
1139
1128
|
|
|
1140
|
-
def log(sql, name = "SQL", binds = [], type_casted_binds = [],
|
|
1129
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], async: false, &block) # :doc:
|
|
1141
1130
|
@instrumenter.instrument(
|
|
1142
1131
|
"sql.active_record",
|
|
1143
1132
|
sql: sql,
|
|
1144
1133
|
name: name,
|
|
1145
1134
|
binds: binds,
|
|
1146
1135
|
type_casted_binds: type_casted_binds,
|
|
1147
|
-
statement_name: statement_name,
|
|
1148
1136
|
async: async,
|
|
1149
1137
|
connection: self,
|
|
1150
1138
|
transaction: current_transaction.user_transaction.presence,
|
|
@@ -1155,13 +1143,6 @@ module ActiveRecord
|
|
|
1155
1143
|
raise ex.set_query(sql, binds)
|
|
1156
1144
|
end
|
|
1157
1145
|
|
|
1158
|
-
def transform_query(sql)
|
|
1159
|
-
ActiveRecord.query_transformers.each do |transformer|
|
|
1160
|
-
sql = transformer.call(sql, self)
|
|
1161
|
-
end
|
|
1162
|
-
sql
|
|
1163
|
-
end
|
|
1164
|
-
|
|
1165
1146
|
def translate_exception(exception, message:, sql:, binds:)
|
|
1166
1147
|
# override in derived class
|
|
1167
1148
|
case exception
|
|
@@ -1172,10 +1153,6 @@ module ActiveRecord
|
|
|
1172
1153
|
end
|
|
1173
1154
|
end
|
|
1174
1155
|
|
|
1175
|
-
def without_prepared_statement?(binds)
|
|
1176
|
-
!prepared_statements || binds.empty?
|
|
1177
|
-
end
|
|
1178
|
-
|
|
1179
1156
|
def column_for(table_name, column_name)
|
|
1180
1157
|
column_name = column_name.to_s
|
|
1181
1158
|
columns(table_name).detect { |c| c.name == column_name } ||
|
|
@@ -1227,13 +1204,6 @@ module ActiveRecord
|
|
|
1227
1204
|
check_version
|
|
1228
1205
|
end
|
|
1229
1206
|
|
|
1230
|
-
def attempt_configure_connection
|
|
1231
|
-
configure_connection
|
|
1232
|
-
rescue Exception # Need to handle things such as Timeout::ExitException
|
|
1233
|
-
disconnect!
|
|
1234
|
-
raise
|
|
1235
|
-
end
|
|
1236
|
-
|
|
1237
1207
|
def default_prepared_statements
|
|
1238
1208
|
true
|
|
1239
1209
|
end
|
|
@@ -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
|
|
|
@@ -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?
|
|
@@ -174,10 +174,6 @@ module ActiveRecord
|
|
|
174
174
|
mariadb? && database_version >= "10.5.0"
|
|
175
175
|
end
|
|
176
176
|
|
|
177
|
-
def return_value_after_insert?(column) # :nodoc:
|
|
178
|
-
supports_insert_returning? ? column.auto_populated? : column.auto_increment?
|
|
179
|
-
end
|
|
180
|
-
|
|
181
177
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
|
182
178
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
|
183
179
|
end
|
|
@@ -201,12 +197,6 @@ module ActiveRecord
|
|
|
201
197
|
|
|
202
198
|
# HELPER METHODS ===========================================
|
|
203
199
|
|
|
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
200
|
# Must return the MySQL error number from the exception, if the exception has an
|
|
211
201
|
# error number.
|
|
212
202
|
def error_number(exception) # :nodoc:
|
|
@@ -230,24 +220,19 @@ module ActiveRecord
|
|
|
230
220
|
# DATABASE STATEMENTS ======================================
|
|
231
221
|
#++
|
|
232
222
|
|
|
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
223
|
def begin_db_transaction # :nodoc:
|
|
245
224
|
internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
246
225
|
end
|
|
247
226
|
|
|
248
227
|
def begin_isolated_db_transaction(isolation) # :nodoc:
|
|
249
|
-
|
|
250
|
-
|
|
228
|
+
# From MySQL manual: The [SET TRANSACTION] statement applies only to the next single transaction performed within the session.
|
|
229
|
+
# So we don't need to implement #reset_isolation_level
|
|
230
|
+
execute_batch(
|
|
231
|
+
["SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "BEGIN"],
|
|
232
|
+
"TRANSACTION",
|
|
233
|
+
allow_retry: true,
|
|
234
|
+
materialize_transactions: false,
|
|
235
|
+
)
|
|
251
236
|
end
|
|
252
237
|
|
|
253
238
|
def commit_db_transaction # :nodoc:
|
|
@@ -347,7 +332,7 @@ module ActiveRecord
|
|
|
347
332
|
rename_table_indexes(table_name, new_name, **options)
|
|
348
333
|
end
|
|
349
334
|
|
|
350
|
-
# Drops a table from the database.
|
|
335
|
+
# Drops a table or tables from the database.
|
|
351
336
|
#
|
|
352
337
|
# [<tt>:force</tt>]
|
|
353
338
|
# Set to +:cascade+ to drop dependent objects as well.
|
|
@@ -361,10 +346,10 @@ module ActiveRecord
|
|
|
361
346
|
#
|
|
362
347
|
# Although this command ignores most +options+ and the block if one is given,
|
|
363
348
|
# 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}"
|
|
349
|
+
# 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.
|
|
350
|
+
def drop_table(*table_names, **options)
|
|
351
|
+
table_names.each { |table_name| schema_cache.clear_data_source_cache!(table_name.to_s) }
|
|
352
|
+
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
353
|
end
|
|
369
354
|
|
|
370
355
|
def rename_index(table_name, old_name, new_name)
|
|
@@ -418,11 +403,7 @@ module ActiveRecord
|
|
|
418
403
|
type ||= column.sql_type
|
|
419
404
|
|
|
420
405
|
unless options.key?(:default)
|
|
421
|
-
options[:default] =
|
|
422
|
-
-> { column.default_function }
|
|
423
|
-
else
|
|
424
|
-
column.default
|
|
425
|
-
end
|
|
406
|
+
options[:default] = column.default
|
|
426
407
|
end
|
|
427
408
|
|
|
428
409
|
unless options.key?(:null)
|
|
@@ -588,7 +569,7 @@ module ActiveRecord
|
|
|
588
569
|
|
|
589
570
|
# SHOW VARIABLES LIKE 'name'
|
|
590
571
|
def show_variable(name)
|
|
591
|
-
query_value("SELECT @@#{name}", "SCHEMA")
|
|
572
|
+
query_value("SELECT @@#{name}", "SCHEMA", materialize_transactions: false, allow_retry: true)
|
|
592
573
|
rescue ActiveRecord::StatementInvalid
|
|
593
574
|
nil
|
|
594
575
|
end
|
|
@@ -647,26 +628,22 @@ module ActiveRecord
|
|
|
647
628
|
end
|
|
648
629
|
|
|
649
630
|
def build_insert_sql(insert) # :nodoc:
|
|
650
|
-
|
|
651
|
-
no_op_column = quote_column_name(insert.keys.first) if insert.keys.first
|
|
631
|
+
no_op_column = quote_column_name(insert.keys.first)
|
|
652
632
|
|
|
653
633
|
# MySQL 8.0.19 replaces `VALUES(<expression>)` clauses with row and column alias names, see https://dev.mysql.com/worklog/task/?id=6312 .
|
|
654
634
|
# then MySQL 8.0.20 deprecates the `VALUES(<expression>)` see https://dev.mysql.com/worklog/task/?id=13325 .
|
|
655
635
|
if supports_insert_raw_alias_syntax?
|
|
656
|
-
quoted_table_name = insert.model.quoted_table_name
|
|
657
636
|
values_alias = quote_table_name("#{insert.model.table_name.parameterize}_values")
|
|
658
637
|
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"
|
|
659
638
|
|
|
660
639
|
if insert.skip_duplicates?
|
|
661
|
-
|
|
662
|
-
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{quoted_table_name}.#{no_op_column}"
|
|
663
|
-
end
|
|
640
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{values_alias}.#{no_op_column}"
|
|
664
641
|
elsif insert.update_duplicates?
|
|
665
642
|
if insert.raw_update_sql?
|
|
666
643
|
sql = +"INSERT #{insert.into} #{insert.values_list} ON DUPLICATE KEY UPDATE #{insert.raw_update_sql}"
|
|
667
644
|
else
|
|
668
645
|
sql << " ON DUPLICATE KEY UPDATE "
|
|
669
|
-
sql << insert.touch_model_timestamps_unless { |column| "#{quoted_table_name}.#{column}<=>#{values_alias}.#{column}" }
|
|
646
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column}<=>#{values_alias}.#{column}" }
|
|
670
647
|
sql << insert.updatable_columns.map { |column| "#{column}=#{values_alias}.#{column}" }.join(",")
|
|
671
648
|
end
|
|
672
649
|
end
|
|
@@ -674,9 +651,7 @@ module ActiveRecord
|
|
|
674
651
|
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
|
675
652
|
|
|
676
653
|
if insert.skip_duplicates?
|
|
677
|
-
|
|
678
|
-
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
|
679
|
-
end
|
|
654
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
|
680
655
|
elsif insert.update_duplicates?
|
|
681
656
|
sql << " ON DUPLICATE KEY UPDATE "
|
|
682
657
|
if insert.raw_update_sql?
|
|
@@ -693,8 +668,8 @@ module ActiveRecord
|
|
|
693
668
|
end
|
|
694
669
|
|
|
695
670
|
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.
|
|
671
|
+
if database_version < "5.6.4"
|
|
672
|
+
raise DatabaseVersionError, "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.6.4."
|
|
698
673
|
end
|
|
699
674
|
end
|
|
700
675
|
|
|
@@ -767,7 +742,9 @@ module ActiveRecord
|
|
|
767
742
|
|
|
768
743
|
private
|
|
769
744
|
def strip_whitespace_characters(expression)
|
|
770
|
-
expression.gsub(
|
|
745
|
+
expression = expression.gsub(/\\n|\\\\/, "")
|
|
746
|
+
expression = expression.gsub(/\s{2,}/, " ")
|
|
747
|
+
expression
|
|
771
748
|
end
|
|
772
749
|
|
|
773
750
|
def extended_type_map_key
|
|
@@ -799,11 +776,6 @@ module ActiveRecord
|
|
|
799
776
|
warning.level == "Note" || super
|
|
800
777
|
end
|
|
801
778
|
|
|
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
779
|
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
|
|
808
780
|
ER_DB_CREATE_EXISTS = 1007
|
|
809
781
|
ER_FILSORT_ABORT = 1028
|
|
@@ -973,13 +945,11 @@ module ActiveRecord
|
|
|
973
945
|
end.join(", ")
|
|
974
946
|
|
|
975
947
|
# ...and send them all in one query
|
|
976
|
-
|
|
948
|
+
raw_execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
|
977
949
|
end
|
|
978
950
|
|
|
979
951
|
def column_definitions(table_name) # :nodoc:
|
|
980
|
-
|
|
981
|
-
each_hash(result)
|
|
982
|
-
end
|
|
952
|
+
internal_exec_query("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", "SCHEMA")
|
|
983
953
|
end
|
|
984
954
|
|
|
985
955
|
def create_table_info(table_name) # :nodoc:
|
|
@@ -77,14 +77,6 @@ module ActiveRecord
|
|
|
77
77
|
0
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
def quoted_date(value)
|
|
81
|
-
if supports_datetime_with_precision?
|
|
82
|
-
super
|
|
83
|
-
else
|
|
84
|
-
super.sub(/\.\d{6}\z/, "")
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
80
|
def quoted_binary(value)
|
|
89
81
|
"x'#{value.hex}'"
|
|
90
82
|
end
|
|
@@ -110,13 +102,7 @@ module ActiveRecord
|
|
|
110
102
|
else
|
|
111
103
|
value.getlocal
|
|
112
104
|
end
|
|
113
|
-
when Time
|
|
114
|
-
if default_timezone == :utc
|
|
115
|
-
value.utc? ? value : value.getutc
|
|
116
|
-
else
|
|
117
|
-
value.utc? ? value.getlocal : value
|
|
118
|
-
end
|
|
119
|
-
when Date
|
|
105
|
+
when Date, Time
|
|
120
106
|
value
|
|
121
107
|
else
|
|
122
108
|
super
|
|
@@ -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
|
|
|
@@ -182,12 +180,12 @@ module ActiveRecord
|
|
|
182
180
|
end
|
|
183
181
|
|
|
184
182
|
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[
|
|
183
|
+
field_name = field.fetch("Field")
|
|
184
|
+
type_metadata = fetch_type_metadata(field["Type"], field["Extra"])
|
|
185
|
+
default, default_function = field["Default"], nil
|
|
188
186
|
|
|
189
187
|
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[
|
|
188
|
+
default = "#{default} ON UPDATE #{default}" if /on update CURRENT_TIMESTAMP/i.match?(field["Extra"])
|
|
191
189
|
default, default_function = nil, default
|
|
192
190
|
elsif type_metadata.extra == "DEFAULT_GENERATED"
|
|
193
191
|
default = +"(#{default})" unless default.start_with?("(")
|
|
@@ -203,13 +201,13 @@ module ActiveRecord
|
|
|
203
201
|
end
|
|
204
202
|
|
|
205
203
|
MySQL::Column.new(
|
|
206
|
-
field[
|
|
204
|
+
field["Field"],
|
|
207
205
|
default,
|
|
208
206
|
type_metadata,
|
|
209
|
-
field[
|
|
207
|
+
field["Null"] == "YES",
|
|
210
208
|
default_function,
|
|
211
|
-
collation: field[
|
|
212
|
-
comment: field[
|
|
209
|
+
collation: field["Collation"],
|
|
210
|
+
comment: field["Comment"].presence
|
|
213
211
|
)
|
|
214
212
|
end
|
|
215
213
|
|