activerecord 6.0.0.beta2 → 6.0.2.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 +471 -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 +114 -34
- 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 +10 -7
- 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 +68 -27
- 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,13 +79,15 @@ 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!
|
85
86
|
|
86
87
|
def self.type_cast_config_to_integer(config)
|
87
|
-
if config.
|
88
|
+
if config.nil?
|
89
|
+
config
|
90
|
+
elsif config.is_a?(Integer)
|
88
91
|
config
|
89
92
|
elsif SIMPLE_INT.match?(config)
|
90
93
|
config.to_i
|
@@ -106,6 +109,14 @@ module ActiveRecord
|
|
106
109
|
Regexp.union(*parts)
|
107
110
|
end
|
108
111
|
|
112
|
+
def self.quoted_column_names # :nodoc:
|
113
|
+
@quoted_column_names ||= {}
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.quoted_table_names # :nodoc:
|
117
|
+
@quoted_table_names ||= {}
|
118
|
+
end
|
119
|
+
|
109
120
|
def initialize(connection, logger = nil, config = {}) # :nodoc:
|
110
121
|
super()
|
111
122
|
|
@@ -114,12 +125,10 @@ module ActiveRecord
|
|
114
125
|
@instrumenter = ActiveSupport::Notifications.instrumenter
|
115
126
|
@logger = logger
|
116
127
|
@config = config
|
117
|
-
@pool =
|
128
|
+
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
118
129
|
@idle_since = Concurrent.monotonic_time
|
119
|
-
@schema_cache = SchemaCache.new self
|
120
|
-
@quoted_column_names, @quoted_table_names = {}, {}
|
121
|
-
@prevent_writes = false
|
122
130
|
@visitor = arel_visitor
|
131
|
+
@statements = build_statement_pool
|
123
132
|
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
124
133
|
|
125
134
|
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
@@ -132,8 +141,6 @@ module ActiveRecord
|
|
132
141
|
@advisory_locks_enabled = self.class.type_cast_config_to_boolean(
|
133
142
|
config.fetch(:advisory_locks, true)
|
134
143
|
)
|
135
|
-
|
136
|
-
check_version
|
137
144
|
end
|
138
145
|
|
139
146
|
def replica?
|
@@ -145,19 +152,7 @@ module ActiveRecord
|
|
145
152
|
# Returns true if the connection is a replica, or if +prevent_writes+
|
146
153
|
# is set to true.
|
147
154
|
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
|
155
|
+
replica? || ActiveRecord::Base.connection_handler.prevent_writes
|
161
156
|
end
|
162
157
|
|
163
158
|
def migrations_paths # :nodoc:
|
@@ -165,14 +160,40 @@ module ActiveRecord
|
|
165
160
|
end
|
166
161
|
|
167
162
|
def migration_context # :nodoc:
|
168
|
-
MigrationContext.new(migrations_paths)
|
163
|
+
MigrationContext.new(migrations_paths, schema_migration)
|
164
|
+
end
|
165
|
+
|
166
|
+
def schema_migration # :nodoc:
|
167
|
+
@schema_migration ||= begin
|
168
|
+
conn = self
|
169
|
+
spec_name = conn.pool.spec.name
|
170
|
+
name = "#{spec_name}::SchemaMigration"
|
171
|
+
|
172
|
+
Class.new(ActiveRecord::SchemaMigration) do
|
173
|
+
define_singleton_method(:name) { name }
|
174
|
+
define_singleton_method(:to_s) { name }
|
175
|
+
|
176
|
+
self.connection_specification_name = spec_name
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def prepared_statements
|
182
|
+
@prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
|
183
|
+
end
|
184
|
+
|
185
|
+
def prepared_statements_disabled_cache # :nodoc:
|
186
|
+
Thread.current[:ar_prepared_statements_disabled_cache] ||= Set.new
|
169
187
|
end
|
170
188
|
|
171
189
|
class Version
|
172
190
|
include Comparable
|
173
191
|
|
174
|
-
|
192
|
+
attr_reader :full_version_string
|
193
|
+
|
194
|
+
def initialize(version_string, full_version_string = nil)
|
175
195
|
@version = version_string.split(".").map(&:to_i)
|
196
|
+
@full_version_string = full_version_string
|
176
197
|
end
|
177
198
|
|
178
199
|
def <=>(version_string)
|
@@ -204,9 +225,13 @@ module ActiveRecord
|
|
204
225
|
@owner = Thread.current
|
205
226
|
end
|
206
227
|
|
228
|
+
def schema_cache
|
229
|
+
@pool.get_schema_cache(self)
|
230
|
+
end
|
231
|
+
|
207
232
|
def schema_cache=(cache)
|
208
233
|
cache.connection = self
|
209
|
-
@
|
234
|
+
@pool.set_schema_cache(cache)
|
210
235
|
end
|
211
236
|
|
212
237
|
# this method must only be called while holding connection pool's mutex
|
@@ -245,10 +270,10 @@ module ActiveRecord
|
|
245
270
|
end
|
246
271
|
|
247
272
|
def unprepared_statement
|
248
|
-
|
273
|
+
cache = prepared_statements_disabled_cache.add(object_id) if @prepared_statements
|
249
274
|
yield
|
250
275
|
ensure
|
251
|
-
|
276
|
+
cache&.delete(object_id)
|
252
277
|
end
|
253
278
|
|
254
279
|
# Returns the human-readable name of the adapter. Use mixed case - one
|
@@ -257,6 +282,11 @@ module ActiveRecord
|
|
257
282
|
self.class::ADAPTER_NAME
|
258
283
|
end
|
259
284
|
|
285
|
+
# Does the database for this adapter exist?
|
286
|
+
def self.database_exists?(config)
|
287
|
+
raise NotImplementedError
|
288
|
+
end
|
289
|
+
|
260
290
|
# Does this adapter support DDL rollbacks in transactions? That is, would
|
261
291
|
# CREATE TABLE or ALTER TABLE get rolled back by a transaction?
|
262
292
|
def supports_ddl_transactions?
|
@@ -383,10 +413,35 @@ module ActiveRecord
|
|
383
413
|
false
|
384
414
|
end
|
385
415
|
|
416
|
+
# Does this adapter support optimizer hints?
|
417
|
+
def supports_optimizer_hints?
|
418
|
+
false
|
419
|
+
end
|
420
|
+
|
421
|
+
def supports_common_table_expressions?
|
422
|
+
false
|
423
|
+
end
|
424
|
+
|
386
425
|
def supports_lazy_transactions?
|
387
426
|
false
|
388
427
|
end
|
389
428
|
|
429
|
+
def supports_insert_returning?
|
430
|
+
false
|
431
|
+
end
|
432
|
+
|
433
|
+
def supports_insert_on_duplicate_skip?
|
434
|
+
false
|
435
|
+
end
|
436
|
+
|
437
|
+
def supports_insert_on_duplicate_update?
|
438
|
+
false
|
439
|
+
end
|
440
|
+
|
441
|
+
def supports_insert_conflict_target?
|
442
|
+
false
|
443
|
+
end
|
444
|
+
|
390
445
|
# This is meant to be implemented by the adapters that support extensions
|
391
446
|
def disable_extension(name)
|
392
447
|
end
|
@@ -464,6 +519,9 @@ module ActiveRecord
|
|
464
519
|
#
|
465
520
|
# Prevent @connection's finalizer from touching the socket, or
|
466
521
|
# otherwise communicating with its server, when it is collected.
|
522
|
+
if schema_cache.connection == self
|
523
|
+
schema_cache.connection = nil
|
524
|
+
end
|
467
525
|
end
|
468
526
|
|
469
527
|
# Reset the state of this connection, directing the DBMS to clear
|
@@ -476,11 +534,9 @@ module ActiveRecord
|
|
476
534
|
# this should be overridden by concrete adapters
|
477
535
|
end
|
478
536
|
|
479
|
-
|
480
|
-
# Clear any caching the database adapter may be doing, for example
|
481
|
-
# clearing the prepared statement cache. This is database specific.
|
537
|
+
# Clear any caching the database adapter may be doing.
|
482
538
|
def clear_cache!
|
483
|
-
|
539
|
+
@lock.synchronize { @statements.clear } if @statements
|
484
540
|
end
|
485
541
|
|
486
542
|
# Returns true if its required to reload the connection between requests for development mode.
|
@@ -506,8 +562,8 @@ module ActiveRecord
|
|
506
562
|
@connection
|
507
563
|
end
|
508
564
|
|
509
|
-
def default_uniqueness_comparison(attribute, value) # :nodoc:
|
510
|
-
|
565
|
+
def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
|
566
|
+
attribute.eq(value)
|
511
567
|
end
|
512
568
|
|
513
569
|
def case_sensitive_comparison(attribute, value) # :nodoc:
|
@@ -542,10 +598,31 @@ module ActiveRecord
|
|
542
598
|
index.using.nil?
|
543
599
|
end
|
544
600
|
|
545
|
-
|
546
|
-
|
601
|
+
# Called by ActiveRecord::InsertAll,
|
602
|
+
# Passed an instance of ActiveRecord::InsertAll::Builder,
|
603
|
+
# This method implements standard bulk inserts for all databases, but
|
604
|
+
# should be overridden by adapters to implement common features with
|
605
|
+
# non-standard syntax like handling duplicates or returning values.
|
606
|
+
def build_insert_sql(insert) # :nodoc:
|
607
|
+
if insert.skip_duplicates? || insert.update_duplicates?
|
608
|
+
raise NotImplementedError, "#{self.class} should define `build_insert_sql` to implement adapter-specific logic for handling duplicates during INSERT"
|
547
609
|
end
|
548
610
|
|
611
|
+
"INSERT #{insert.into} #{insert.values_list}"
|
612
|
+
end
|
613
|
+
|
614
|
+
def get_database_version # :nodoc:
|
615
|
+
end
|
616
|
+
|
617
|
+
def database_version # :nodoc:
|
618
|
+
schema_cache.database_version
|
619
|
+
end
|
620
|
+
|
621
|
+
def check_version # :nodoc:
|
622
|
+
end
|
623
|
+
|
624
|
+
private
|
625
|
+
|
549
626
|
def type_map
|
550
627
|
@type_map ||= Type::TypeMap.new.tap do |mapping|
|
551
628
|
initialize_type_map(mapping)
|
@@ -689,6 +766,9 @@ module ActiveRecord
|
|
689
766
|
def arel_visitor
|
690
767
|
Arel::Visitors::ToSql.new(self)
|
691
768
|
end
|
769
|
+
|
770
|
+
def build_statement_pool
|
771
|
+
end
|
692
772
|
end
|
693
773
|
end
|
694
774
|
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:
|