activerecord 6.0.0.beta3 → 6.0.2.rc2
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 +466 -9
- data/README.rdoc +3 -1
- data/lib/active_record.rb +0 -1
- data/lib/active_record/association_relation.rb +15 -6
- data/lib/active_record/associations.rb +4 -3
- data/lib/active_record/associations/association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +5 -2
- data/lib/active_record/associations/builder/collection_association.rb +5 -15
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +6 -2
- data/lib/active_record/associations/collection_proxy.rb +2 -2
- data/lib/active_record/associations/has_many_through_association.rb +4 -11
- data/lib/active_record/associations/join_dependency.rb +14 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +12 -3
- data/lib/active_record/associations/preloader.rb +13 -8
- data/lib/active_record/associations/preloader/association.rb +34 -30
- data/lib/active_record/associations/preloader/through_association.rb +48 -28
- data/lib/active_record/attribute_methods.rb +3 -53
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +47 -14
- data/lib/active_record/attribute_methods/primary_key.rb +7 -15
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +3 -9
- data/lib/active_record/attribute_methods/write.rb +6 -12
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +21 -7
- data/lib/active_record/base.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -11
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +88 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -7
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +79 -22
- data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -4
- data/lib/active_record/connection_adapters/abstract_adapter.rb +111 -33
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +78 -73
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +48 -8
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -5
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +9 -6
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -5
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +39 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +34 -38
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +67 -26
- data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -114
- data/lib/active_record/connection_handling.rb +31 -13
- data/lib/active_record/core.rb +23 -24
- data/lib/active_record/database_configurations.rb +73 -44
- data/lib/active_record/database_configurations/hash_config.rb +11 -11
- data/lib/active_record/database_configurations/url_config.rb +12 -12
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +15 -0
- data/lib/active_record/errors.rb +1 -1
- data/lib/active_record/fixtures.rb +11 -6
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +13 -1
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +3 -4
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/middleware/database_selector.rb +3 -3
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -6
- data/lib/active_record/migration.rb +62 -44
- data/lib/active_record/migration/command_recorder.rb +28 -14
- data/lib/active_record/migration/compatibility.rb +10 -0
- data/lib/active_record/model_schema.rb +3 -0
- data/lib/active_record/persistence.rb +206 -13
- data/lib/active_record/querying.rb +17 -12
- data/lib/active_record/railtie.rb +0 -1
- data/lib/active_record/railties/databases.rake +127 -25
- data/lib/active_record/reflection.rb +3 -3
- data/lib/active_record/relation.rb +99 -20
- data/lib/active_record/relation/calculations.rb +38 -40
- data/lib/active_record/relation/delegation.rb +22 -30
- data/lib/active_record/relation/finder_methods.rb +17 -12
- data/lib/active_record/relation/merger.rb +11 -16
- data/lib/active_record/relation/query_methods.rb +228 -76
- data/lib/active_record/relation/where_clause.rb +9 -5
- data/lib/active_record/sanitization.rb +33 -4
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +10 -1
- data/lib/active_record/schema_migration.rb +1 -1
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/store.rb +48 -0
- data/lib/active_record/table_metadata.rb +9 -13
- data/lib/active_record/tasks/database_tasks.rb +109 -6
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -1
- data/lib/active_record/test_databases.rb +1 -16
- data/lib/active_record/test_fixtures.rb +1 -0
- data/lib/active_record/timestamp.rb +26 -16
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +56 -46
- data/lib/active_record/type_caster/connection.rb +16 -10
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +3 -5
- data/lib/arel.rb +12 -5
- data/lib/arel/insert_manager.rb +3 -3
- data/lib/arel/nodes.rb +2 -1
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/select_core.rb +16 -12
- data/lib/arel/nodes/unary.rb +1 -0
- data/lib/arel/nodes/values_list.rb +2 -17
- data/lib/arel/select_manager.rb +10 -10
- data/lib/arel/visitors/depth_first.rb +7 -2
- data/lib/arel/visitors/dot.rb +7 -2
- data/lib/arel/visitors/ibm_db.rb +13 -0
- data/lib/arel/visitors/informix.rb +6 -0
- data/lib/arel/visitors/mssql.rb +15 -1
- data/lib/arel/visitors/oracle12.rb +4 -5
- data/lib/arel/visitors/postgresql.rb +4 -10
- data/lib/arel/visitors/to_sql.rb +107 -131
- data/lib/arel/visitors/visitor.rb +9 -5
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +16 -12
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/arel/nodes/values.rb +0 -16
@@ -98,9 +98,13 @@ module ActiveRecord
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def rollback_records
|
101
|
-
ite = records.uniq
|
101
|
+
ite = records.uniq(&:object_id)
|
102
|
+
already_run_callbacks = {}
|
102
103
|
while record = ite.shift
|
103
|
-
record.
|
104
|
+
trigger_callbacks = record.trigger_transactional_callbacks?
|
105
|
+
should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
|
106
|
+
already_run_callbacks[record] ||= trigger_callbacks
|
107
|
+
record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks)
|
104
108
|
end
|
105
109
|
ensure
|
106
110
|
ite.each do |i|
|
@@ -113,10 +117,14 @@ module ActiveRecord
|
|
113
117
|
end
|
114
118
|
|
115
119
|
def commit_records
|
116
|
-
ite = records.uniq
|
120
|
+
ite = records.uniq(&:object_id)
|
121
|
+
already_run_callbacks = {}
|
117
122
|
while record = ite.shift
|
118
123
|
if @run_commit_callbacks
|
119
|
-
record.
|
124
|
+
trigger_callbacks = record.trigger_transactional_callbacks?
|
125
|
+
should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
|
126
|
+
already_run_callbacks[record] ||= trigger_callbacks
|
127
|
+
record.committed!(should_run_callbacks: should_run_callbacks)
|
120
128
|
else
|
121
129
|
# if not running callbacks, only adds the record to the parent transaction
|
122
130
|
connection.add_transaction_record(record)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "set"
|
3
4
|
require "active_record/connection_adapters/determine_if_preparable_visitor"
|
4
5
|
require "active_record/connection_adapters/schema_cache"
|
5
6
|
require "active_record/connection_adapters/sql_type_metadata"
|
@@ -78,7 +79,7 @@ module ActiveRecord
|
|
78
79
|
SIMPLE_INT = /\A\d+\z/
|
79
80
|
|
80
81
|
attr_accessor :pool
|
81
|
-
attr_reader :
|
82
|
+
attr_reader :visitor, :owner, :logger, :lock
|
82
83
|
alias :in_use? :owner
|
83
84
|
|
84
85
|
set_callback :checkin, :after, :enable_lazy_transactions!
|
@@ -106,6 +107,14 @@ module ActiveRecord
|
|
106
107
|
Regexp.union(*parts)
|
107
108
|
end
|
108
109
|
|
110
|
+
def self.quoted_column_names # :nodoc:
|
111
|
+
@quoted_column_names ||= {}
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.quoted_table_names # :nodoc:
|
115
|
+
@quoted_table_names ||= {}
|
116
|
+
end
|
117
|
+
|
109
118
|
def initialize(connection, logger = nil, config = {}) # :nodoc:
|
110
119
|
super()
|
111
120
|
|
@@ -114,12 +123,10 @@ module ActiveRecord
|
|
114
123
|
@instrumenter = ActiveSupport::Notifications.instrumenter
|
115
124
|
@logger = logger
|
116
125
|
@config = config
|
117
|
-
@pool =
|
126
|
+
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
118
127
|
@idle_since = Concurrent.monotonic_time
|
119
|
-
@schema_cache = SchemaCache.new self
|
120
|
-
@quoted_column_names, @quoted_table_names = {}, {}
|
121
|
-
@prevent_writes = false
|
122
128
|
@visitor = arel_visitor
|
129
|
+
@statements = build_statement_pool
|
123
130
|
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
124
131
|
|
125
132
|
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
@@ -132,8 +139,6 @@ module ActiveRecord
|
|
132
139
|
@advisory_locks_enabled = self.class.type_cast_config_to_boolean(
|
133
140
|
config.fetch(:advisory_locks, true)
|
134
141
|
)
|
135
|
-
|
136
|
-
check_version
|
137
142
|
end
|
138
143
|
|
139
144
|
def replica?
|
@@ -145,19 +150,7 @@ module ActiveRecord
|
|
145
150
|
# Returns true if the connection is a replica, or if +prevent_writes+
|
146
151
|
# is set to true.
|
147
152
|
def preventing_writes?
|
148
|
-
replica? || prevent_writes
|
149
|
-
end
|
150
|
-
|
151
|
-
# Prevent writing to the database regardless of role.
|
152
|
-
#
|
153
|
-
# In some cases you may want to prevent writes to the database
|
154
|
-
# even if you are on a database that can write. `while_preventing_writes`
|
155
|
-
# will prevent writes to the database for the duration of the block.
|
156
|
-
def while_preventing_writes
|
157
|
-
original, @prevent_writes = @prevent_writes, true
|
158
|
-
yield
|
159
|
-
ensure
|
160
|
-
@prevent_writes = original
|
153
|
+
replica? || ActiveRecord::Base.connection_handler.prevent_writes
|
161
154
|
end
|
162
155
|
|
163
156
|
def migrations_paths # :nodoc:
|
@@ -165,14 +158,40 @@ module ActiveRecord
|
|
165
158
|
end
|
166
159
|
|
167
160
|
def migration_context # :nodoc:
|
168
|
-
MigrationContext.new(migrations_paths)
|
161
|
+
MigrationContext.new(migrations_paths, schema_migration)
|
162
|
+
end
|
163
|
+
|
164
|
+
def schema_migration # :nodoc:
|
165
|
+
@schema_migration ||= begin
|
166
|
+
conn = self
|
167
|
+
spec_name = conn.pool.spec.name
|
168
|
+
name = "#{spec_name}::SchemaMigration"
|
169
|
+
|
170
|
+
Class.new(ActiveRecord::SchemaMigration) do
|
171
|
+
define_singleton_method(:name) { name }
|
172
|
+
define_singleton_method(:to_s) { name }
|
173
|
+
|
174
|
+
self.connection_specification_name = spec_name
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def prepared_statements
|
180
|
+
@prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
|
181
|
+
end
|
182
|
+
|
183
|
+
def prepared_statements_disabled_cache # :nodoc:
|
184
|
+
Thread.current[:ar_prepared_statements_disabled_cache] ||= Set.new
|
169
185
|
end
|
170
186
|
|
171
187
|
class Version
|
172
188
|
include Comparable
|
173
189
|
|
174
|
-
|
190
|
+
attr_reader :full_version_string
|
191
|
+
|
192
|
+
def initialize(version_string, full_version_string = nil)
|
175
193
|
@version = version_string.split(".").map(&:to_i)
|
194
|
+
@full_version_string = full_version_string
|
176
195
|
end
|
177
196
|
|
178
197
|
def <=>(version_string)
|
@@ -204,9 +223,13 @@ module ActiveRecord
|
|
204
223
|
@owner = Thread.current
|
205
224
|
end
|
206
225
|
|
226
|
+
def schema_cache
|
227
|
+
@pool.get_schema_cache(self)
|
228
|
+
end
|
229
|
+
|
207
230
|
def schema_cache=(cache)
|
208
231
|
cache.connection = self
|
209
|
-
@
|
232
|
+
@pool.set_schema_cache(cache)
|
210
233
|
end
|
211
234
|
|
212
235
|
# this method must only be called while holding connection pool's mutex
|
@@ -245,10 +268,10 @@ module ActiveRecord
|
|
245
268
|
end
|
246
269
|
|
247
270
|
def unprepared_statement
|
248
|
-
|
271
|
+
cache = prepared_statements_disabled_cache.add(object_id) if @prepared_statements
|
249
272
|
yield
|
250
273
|
ensure
|
251
|
-
|
274
|
+
cache&.delete(object_id)
|
252
275
|
end
|
253
276
|
|
254
277
|
# Returns the human-readable name of the adapter. Use mixed case - one
|
@@ -257,6 +280,11 @@ module ActiveRecord
|
|
257
280
|
self.class::ADAPTER_NAME
|
258
281
|
end
|
259
282
|
|
283
|
+
# Does the database for this adapter exist?
|
284
|
+
def self.database_exists?(config)
|
285
|
+
raise NotImplementedError
|
286
|
+
end
|
287
|
+
|
260
288
|
# Does this adapter support DDL rollbacks in transactions? That is, would
|
261
289
|
# CREATE TABLE or ALTER TABLE get rolled back by a transaction?
|
262
290
|
def supports_ddl_transactions?
|
@@ -383,10 +411,35 @@ module ActiveRecord
|
|
383
411
|
false
|
384
412
|
end
|
385
413
|
|
414
|
+
# Does this adapter support optimizer hints?
|
415
|
+
def supports_optimizer_hints?
|
416
|
+
false
|
417
|
+
end
|
418
|
+
|
419
|
+
def supports_common_table_expressions?
|
420
|
+
false
|
421
|
+
end
|
422
|
+
|
386
423
|
def supports_lazy_transactions?
|
387
424
|
false
|
388
425
|
end
|
389
426
|
|
427
|
+
def supports_insert_returning?
|
428
|
+
false
|
429
|
+
end
|
430
|
+
|
431
|
+
def supports_insert_on_duplicate_skip?
|
432
|
+
false
|
433
|
+
end
|
434
|
+
|
435
|
+
def supports_insert_on_duplicate_update?
|
436
|
+
false
|
437
|
+
end
|
438
|
+
|
439
|
+
def supports_insert_conflict_target?
|
440
|
+
false
|
441
|
+
end
|
442
|
+
|
390
443
|
# This is meant to be implemented by the adapters that support extensions
|
391
444
|
def disable_extension(name)
|
392
445
|
end
|
@@ -464,6 +517,9 @@ module ActiveRecord
|
|
464
517
|
#
|
465
518
|
# Prevent @connection's finalizer from touching the socket, or
|
466
519
|
# otherwise communicating with its server, when it is collected.
|
520
|
+
if schema_cache.connection == self
|
521
|
+
schema_cache.connection = nil
|
522
|
+
end
|
467
523
|
end
|
468
524
|
|
469
525
|
# Reset the state of this connection, directing the DBMS to clear
|
@@ -476,11 +532,9 @@ module ActiveRecord
|
|
476
532
|
# this should be overridden by concrete adapters
|
477
533
|
end
|
478
534
|
|
479
|
-
|
480
|
-
# Clear any caching the database adapter may be doing, for example
|
481
|
-
# clearing the prepared statement cache. This is database specific.
|
535
|
+
# Clear any caching the database adapter may be doing.
|
482
536
|
def clear_cache!
|
483
|
-
|
537
|
+
@lock.synchronize { @statements.clear } if @statements
|
484
538
|
end
|
485
539
|
|
486
540
|
# Returns true if its required to reload the connection between requests for development mode.
|
@@ -506,8 +560,8 @@ module ActiveRecord
|
|
506
560
|
@connection
|
507
561
|
end
|
508
562
|
|
509
|
-
def default_uniqueness_comparison(attribute, value) # :nodoc:
|
510
|
-
|
563
|
+
def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
|
564
|
+
attribute.eq(value)
|
511
565
|
end
|
512
566
|
|
513
567
|
def case_sensitive_comparison(attribute, value) # :nodoc:
|
@@ -542,10 +596,31 @@ module ActiveRecord
|
|
542
596
|
index.using.nil?
|
543
597
|
end
|
544
598
|
|
545
|
-
|
546
|
-
|
599
|
+
# Called by ActiveRecord::InsertAll,
|
600
|
+
# Passed an instance of ActiveRecord::InsertAll::Builder,
|
601
|
+
# This method implements standard bulk inserts for all databases, but
|
602
|
+
# should be overridden by adapters to implement common features with
|
603
|
+
# non-standard syntax like handling duplicates or returning values.
|
604
|
+
def build_insert_sql(insert) # :nodoc:
|
605
|
+
if insert.skip_duplicates? || insert.update_duplicates?
|
606
|
+
raise NotImplementedError, "#{self.class} should define `build_insert_sql` to implement adapter-specific logic for handling duplicates during INSERT"
|
547
607
|
end
|
548
608
|
|
609
|
+
"INSERT #{insert.into} #{insert.values_list}"
|
610
|
+
end
|
611
|
+
|
612
|
+
def get_database_version # :nodoc:
|
613
|
+
end
|
614
|
+
|
615
|
+
def database_version # :nodoc:
|
616
|
+
schema_cache.database_version
|
617
|
+
end
|
618
|
+
|
619
|
+
def check_version # :nodoc:
|
620
|
+
end
|
621
|
+
|
622
|
+
private
|
623
|
+
|
549
624
|
def type_map
|
550
625
|
@type_map ||= Type::TypeMap.new.tap do |mapping|
|
551
626
|
initialize_type_map(mapping)
|
@@ -689,6 +764,9 @@ module ActiveRecord
|
|
689
764
|
def arel_visitor
|
690
765
|
Arel::Visitors::ToSql.new(self)
|
691
766
|
end
|
767
|
+
|
768
|
+
def build_statement_pool
|
769
|
+
end
|
692
770
|
end
|
693
771
|
end
|
694
772
|
end
|
@@ -53,28 +53,28 @@ module ActiveRecord
|
|
53
53
|
|
54
54
|
def initialize(connection, logger, connection_options, config)
|
55
55
|
super(connection, logger, config)
|
56
|
-
|
57
|
-
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
|
58
56
|
end
|
59
57
|
|
60
|
-
def
|
61
|
-
|
58
|
+
def get_database_version #:nodoc:
|
59
|
+
full_version_string = get_full_version
|
60
|
+
version_string = version_string(full_version_string)
|
61
|
+
Version.new(version_string, full_version_string)
|
62
62
|
end
|
63
63
|
|
64
64
|
def mariadb? # :nodoc:
|
65
65
|
/mariadb/i.match?(full_version)
|
66
66
|
end
|
67
67
|
|
68
|
-
def supports_bulk_alter?
|
68
|
+
def supports_bulk_alter?
|
69
69
|
true
|
70
70
|
end
|
71
71
|
|
72
72
|
def supports_index_sort_order?
|
73
|
-
!mariadb? &&
|
73
|
+
!mariadb? && database_version >= "8.0.1"
|
74
74
|
end
|
75
75
|
|
76
76
|
def supports_expression_index?
|
77
|
-
!mariadb? &&
|
77
|
+
!mariadb? && database_version >= "8.0.13"
|
78
78
|
end
|
79
79
|
|
80
80
|
def supports_transaction_isolation?
|
@@ -98,17 +98,38 @@ module ActiveRecord
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def supports_datetime_with_precision?
|
101
|
-
mariadb? ||
|
101
|
+
mariadb? || database_version >= "5.6.4"
|
102
102
|
end
|
103
103
|
|
104
104
|
def supports_virtual_columns?
|
105
|
-
mariadb? ||
|
105
|
+
mariadb? || database_version >= "5.7.5"
|
106
|
+
end
|
107
|
+
|
108
|
+
# See https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html for more details.
|
109
|
+
def supports_optimizer_hints?
|
110
|
+
!mariadb? && database_version >= "5.7.7"
|
111
|
+
end
|
112
|
+
|
113
|
+
def supports_common_table_expressions?
|
114
|
+
if mariadb?
|
115
|
+
database_version >= "10.2.1"
|
116
|
+
else
|
117
|
+
database_version >= "8.0.1"
|
118
|
+
end
|
106
119
|
end
|
107
120
|
|
108
121
|
def supports_advisory_locks?
|
109
122
|
true
|
110
123
|
end
|
111
124
|
|
125
|
+
def supports_insert_on_duplicate_skip?
|
126
|
+
true
|
127
|
+
end
|
128
|
+
|
129
|
+
def supports_insert_on_duplicate_update?
|
130
|
+
true
|
131
|
+
end
|
132
|
+
|
112
133
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
113
134
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
114
135
|
end
|
@@ -154,10 +175,9 @@ module ActiveRecord
|
|
154
175
|
|
155
176
|
# CONNECTION MANAGEMENT ====================================
|
156
177
|
|
157
|
-
|
158
|
-
def clear_cache!
|
178
|
+
def clear_cache! # :nodoc:
|
159
179
|
reload_type_map
|
160
|
-
|
180
|
+
super
|
161
181
|
end
|
162
182
|
|
163
183
|
#--
|
@@ -264,10 +284,6 @@ module ActiveRecord
|
|
264
284
|
show_variable "collation_database"
|
265
285
|
end
|
266
286
|
|
267
|
-
def truncate(table_name, name = nil)
|
268
|
-
execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
|
269
|
-
end
|
270
|
-
|
271
287
|
def table_comment(table_name) # :nodoc:
|
272
288
|
scope = quoted_scope(table_name)
|
273
289
|
|
@@ -279,22 +295,8 @@ module ActiveRecord
|
|
279
295
|
SQL
|
280
296
|
end
|
281
297
|
|
282
|
-
def
|
283
|
-
|
284
|
-
table, arguments = args.shift, args
|
285
|
-
method = :"#{command}_for_alter"
|
286
|
-
|
287
|
-
if respond_to?(method, true)
|
288
|
-
send(method, table, *arguments)
|
289
|
-
else
|
290
|
-
raise "Unknown method called : #{method}(#{arguments.inspect})"
|
291
|
-
end
|
292
|
-
end.join(", ")
|
293
|
-
|
294
|
-
execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}")
|
295
|
-
end
|
296
|
-
|
297
|
-
def change_table_comment(table_name, comment) #:nodoc:
|
298
|
+
def change_table_comment(table_name, comment_or_changes) # :nodoc:
|
299
|
+
comment = extract_new_comment_value(comment_or_changes)
|
298
300
|
comment = "" if comment.nil?
|
299
301
|
execute("ALTER TABLE #{quote_table_name(table_name)} COMMENT #{quote(comment)}")
|
300
302
|
end
|
@@ -350,7 +352,8 @@ module ActiveRecord
|
|
350
352
|
change_column table_name, column_name, nil, null: null
|
351
353
|
end
|
352
354
|
|
353
|
-
def change_column_comment(table_name, column_name,
|
355
|
+
def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
|
356
|
+
comment = extract_new_comment_value(comment_or_changes)
|
354
357
|
change_column table_name, column_name, nil, comment: comment
|
355
358
|
end
|
356
359
|
|
@@ -445,14 +448,29 @@ module ActiveRecord
|
|
445
448
|
|
446
449
|
query_values(<<~SQL, "SCHEMA")
|
447
450
|
SELECT column_name
|
448
|
-
FROM information_schema.
|
449
|
-
WHERE
|
451
|
+
FROM information_schema.statistics
|
452
|
+
WHERE index_name = 'PRIMARY'
|
450
453
|
AND table_schema = #{scope[:schema]}
|
451
454
|
AND table_name = #{scope[:name]}
|
452
|
-
ORDER BY
|
455
|
+
ORDER BY seq_in_index
|
453
456
|
SQL
|
454
457
|
end
|
455
458
|
|
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
|
+
|
456
474
|
def case_sensitive_comparison(attribute, value) # :nodoc:
|
457
475
|
column = column_for_attribute(attribute)
|
458
476
|
|
@@ -491,45 +509,27 @@ module ActiveRecord
|
|
491
509
|
index.using == :btree || super
|
492
510
|
end
|
493
511
|
|
494
|
-
def
|
495
|
-
|
496
|
-
super { discard_remaining_results }
|
497
|
-
end
|
498
|
-
end
|
512
|
+
def build_insert_sql(insert) # :nodoc:
|
513
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
499
514
|
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
515
|
+
if insert.skip_duplicates?
|
516
|
+
no_op_column = quote_column_name(insert.keys.first)
|
517
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
518
|
+
elsif insert.update_duplicates?
|
519
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
520
|
+
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
505
521
|
end
|
506
522
|
|
507
|
-
|
508
|
-
|
509
|
-
previous_packet = total_sql_chunks.last
|
510
|
-
sql << ";\n"
|
511
|
-
if max_allowed_packet_reached?(sql, previous_packet) || total_sql_chunks.empty?
|
512
|
-
total_sql_chunks << sql
|
513
|
-
else
|
514
|
-
previous_packet << sql
|
515
|
-
end
|
516
|
-
end
|
517
|
-
end
|
523
|
+
sql
|
524
|
+
end
|
518
525
|
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
elsif previous_packet.nil?
|
523
|
-
false
|
524
|
-
else
|
525
|
-
(current_packet.bytesize + previous_packet.bytesize) > max_allowed_packet
|
526
|
-
end
|
526
|
+
def check_version # :nodoc:
|
527
|
+
if database_version < "5.5.8"
|
528
|
+
raise "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
|
527
529
|
end
|
530
|
+
end
|
528
531
|
|
529
|
-
|
530
|
-
bytes_margin = 2
|
531
|
-
@max_allowed_packet ||= (show_variable("max_allowed_packet") - bytes_margin)
|
532
|
-
end
|
532
|
+
private
|
533
533
|
|
534
534
|
def initialize_type_map(m = type_map)
|
535
535
|
super
|
@@ -589,6 +589,7 @@ module ActiveRecord
|
|
589
589
|
end
|
590
590
|
|
591
591
|
# See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
|
592
|
+
ER_FILSORT_ABORT = 1028
|
592
593
|
ER_DUP_ENTRY = 1062
|
593
594
|
ER_NOT_NULL_VIOLATION = 1048
|
594
595
|
ER_NO_REFERENCED_ROW = 1216
|
@@ -630,7 +631,7 @@ module ActiveRecord
|
|
630
631
|
Deadlocked.new(message, sql: sql, binds: binds)
|
631
632
|
when ER_LOCK_WAIT_TIMEOUT
|
632
633
|
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
633
|
-
when ER_QUERY_TIMEOUT
|
634
|
+
when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
|
634
635
|
StatementTimeout.new(message, sql: sql, binds: binds)
|
635
636
|
when ER_QUERY_INTERRUPTED
|
636
637
|
QueryCanceled.new(message, sql: sql, binds: binds)
|
@@ -700,7 +701,7 @@ module ActiveRecord
|
|
700
701
|
end
|
701
702
|
|
702
703
|
def supports_rename_index?
|
703
|
-
mariadb? ? false :
|
704
|
+
mariadb? ? false : database_version >= "5.7.6"
|
704
705
|
end
|
705
706
|
|
706
707
|
def configure_connection
|
@@ -770,6 +771,10 @@ module ActiveRecord
|
|
770
771
|
Arel::Visitors::MySQL.new(self)
|
771
772
|
end
|
772
773
|
|
774
|
+
def build_statement_pool
|
775
|
+
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
776
|
+
end
|
777
|
+
|
773
778
|
def mismatched_foreign_key(message, sql:, binds:)
|
774
779
|
match = %r/
|
775
780
|
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
@@ -794,8 +799,8 @@ module ActiveRecord
|
|
794
799
|
MismatchedForeignKey.new(options)
|
795
800
|
end
|
796
801
|
|
797
|
-
def version_string
|
798
|
-
|
802
|
+
def version_string(full_version_string)
|
803
|
+
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
799
804
|
end
|
800
805
|
|
801
806
|
class MysqlString < Type::String # :nodoc:
|