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.

Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +471 -9
  3. data/README.rdoc +3 -1
  4. data/lib/active_record.rb +0 -1
  5. data/lib/active_record/association_relation.rb +15 -6
  6. data/lib/active_record/associations.rb +4 -3
  7. data/lib/active_record/associations/association.rb +10 -2
  8. data/lib/active_record/associations/builder/association.rb +14 -18
  9. data/lib/active_record/associations/builder/belongs_to.rb +5 -2
  10. data/lib/active_record/associations/builder/collection_association.rb +5 -15
  11. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -1
  12. data/lib/active_record/associations/builder/has_many.rb +2 -0
  13. data/lib/active_record/associations/builder/has_one.rb +35 -1
  14. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  15. data/lib/active_record/associations/collection_association.rb +6 -2
  16. data/lib/active_record/associations/collection_proxy.rb +2 -2
  17. data/lib/active_record/associations/has_many_through_association.rb +4 -11
  18. data/lib/active_record/associations/join_dependency.rb +14 -9
  19. data/lib/active_record/associations/join_dependency/join_association.rb +12 -3
  20. data/lib/active_record/associations/preloader.rb +13 -8
  21. data/lib/active_record/associations/preloader/association.rb +34 -30
  22. data/lib/active_record/associations/preloader/through_association.rb +48 -28
  23. data/lib/active_record/attribute_methods.rb +3 -53
  24. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  25. data/lib/active_record/attribute_methods/dirty.rb +47 -14
  26. data/lib/active_record/attribute_methods/primary_key.rb +7 -15
  27. data/lib/active_record/attribute_methods/query.rb +2 -3
  28. data/lib/active_record/attribute_methods/read.rb +3 -9
  29. data/lib/active_record/attribute_methods/write.rb +6 -12
  30. data/lib/active_record/attributes.rb +13 -0
  31. data/lib/active_record/autosave_association.rb +21 -7
  32. data/lib/active_record/base.rb +0 -1
  33. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -11
  34. data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
  35. data/lib/active_record/connection_adapters/abstract/database_statements.rb +88 -61
  36. data/lib/active_record/connection_adapters/abstract/query_cache.rb +6 -4
  37. data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
  38. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -7
  39. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
  40. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +79 -22
  41. data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -4
  42. data/lib/active_record/connection_adapters/abstract_adapter.rb +114 -34
  43. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +78 -73
  44. data/lib/active_record/connection_adapters/column.rb +17 -13
  45. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  46. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -2
  47. data/lib/active_record/connection_adapters/mysql/database_statements.rb +48 -8
  48. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  49. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -5
  50. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +10 -7
  51. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  52. data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -5
  53. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
  54. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -2
  55. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  56. data/lib/active_record/connection_adapters/postgresql/quoting.rb +39 -2
  57. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +34 -38
  58. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
  59. data/lib/active_record/connection_adapters/postgresql_adapter.rb +68 -27
  60. data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
  61. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  62. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  63. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
  64. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
  65. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -114
  66. data/lib/active_record/connection_handling.rb +31 -13
  67. data/lib/active_record/core.rb +23 -24
  68. data/lib/active_record/database_configurations.rb +73 -44
  69. data/lib/active_record/database_configurations/hash_config.rb +11 -11
  70. data/lib/active_record/database_configurations/url_config.rb +12 -12
  71. data/lib/active_record/dynamic_matchers.rb +1 -1
  72. data/lib/active_record/enum.rb +15 -0
  73. data/lib/active_record/errors.rb +1 -1
  74. data/lib/active_record/fixtures.rb +11 -6
  75. data/lib/active_record/gem_version.rb +2 -2
  76. data/lib/active_record/insert_all.rb +179 -0
  77. data/lib/active_record/integration.rb +13 -1
  78. data/lib/active_record/internal_metadata.rb +5 -1
  79. data/lib/active_record/locking/optimistic.rb +3 -4
  80. data/lib/active_record/log_subscriber.rb +1 -1
  81. data/lib/active_record/middleware/database_selector.rb +3 -3
  82. data/lib/active_record/middleware/database_selector/resolver.rb +4 -6
  83. data/lib/active_record/migration.rb +62 -44
  84. data/lib/active_record/migration/command_recorder.rb +28 -14
  85. data/lib/active_record/migration/compatibility.rb +10 -0
  86. data/lib/active_record/model_schema.rb +3 -0
  87. data/lib/active_record/persistence.rb +206 -13
  88. data/lib/active_record/querying.rb +17 -12
  89. data/lib/active_record/railtie.rb +0 -1
  90. data/lib/active_record/railties/databases.rake +127 -25
  91. data/lib/active_record/reflection.rb +3 -3
  92. data/lib/active_record/relation.rb +99 -20
  93. data/lib/active_record/relation/calculations.rb +38 -40
  94. data/lib/active_record/relation/delegation.rb +22 -30
  95. data/lib/active_record/relation/finder_methods.rb +17 -12
  96. data/lib/active_record/relation/merger.rb +11 -16
  97. data/lib/active_record/relation/query_methods.rb +228 -76
  98. data/lib/active_record/relation/where_clause.rb +9 -5
  99. data/lib/active_record/sanitization.rb +33 -4
  100. data/lib/active_record/schema.rb +1 -1
  101. data/lib/active_record/schema_dumper.rb +10 -1
  102. data/lib/active_record/schema_migration.rb +1 -1
  103. data/lib/active_record/scoping/default.rb +6 -7
  104. data/lib/active_record/scoping/named.rb +3 -2
  105. data/lib/active_record/statement_cache.rb +2 -2
  106. data/lib/active_record/store.rb +48 -0
  107. data/lib/active_record/table_metadata.rb +9 -13
  108. data/lib/active_record/tasks/database_tasks.rb +109 -6
  109. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -1
  110. data/lib/active_record/test_databases.rb +1 -16
  111. data/lib/active_record/test_fixtures.rb +1 -0
  112. data/lib/active_record/timestamp.rb +26 -16
  113. data/lib/active_record/touch_later.rb +4 -2
  114. data/lib/active_record/transactions.rb +56 -46
  115. data/lib/active_record/type_caster/connection.rb +16 -10
  116. data/lib/active_record/validations.rb +1 -0
  117. data/lib/active_record/validations/uniqueness.rb +3 -5
  118. data/lib/arel.rb +12 -5
  119. data/lib/arel/insert_manager.rb +3 -3
  120. data/lib/arel/nodes.rb +2 -1
  121. data/lib/arel/nodes/comment.rb +29 -0
  122. data/lib/arel/nodes/select_core.rb +16 -12
  123. data/lib/arel/nodes/unary.rb +1 -0
  124. data/lib/arel/nodes/values_list.rb +2 -17
  125. data/lib/arel/select_manager.rb +10 -10
  126. data/lib/arel/visitors/depth_first.rb +7 -2
  127. data/lib/arel/visitors/dot.rb +7 -2
  128. data/lib/arel/visitors/ibm_db.rb +13 -0
  129. data/lib/arel/visitors/informix.rb +6 -0
  130. data/lib/arel/visitors/mssql.rb +15 -1
  131. data/lib/arel/visitors/oracle12.rb +4 -5
  132. data/lib/arel/visitors/postgresql.rb +4 -10
  133. data/lib/arel/visitors/to_sql.rb +107 -131
  134. data/lib/arel/visitors/visitor.rb +9 -5
  135. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  136. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  137. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  138. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  139. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  140. metadata +16 -12
  141. data/lib/active_record/collection_cache_key.rb +0 -53
  142. 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.rolledback!(force_restore_state: full_rollback?)
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.committed!
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 :schema_cache, :visitor, :owner, :logger, :lock, :prepared_statements, :prevent_writes
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.is_a?(Integer)
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 = nil
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
- def initialize(version_string)
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
- @schema_cache = cache
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
- old_prepared_statements, @prepared_statements = @prepared_statements, false
273
+ cache = prepared_statements_disabled_cache.add(object_id) if @prepared_statements
249
274
  yield
250
275
  ensure
251
- @prepared_statements = old_prepared_statements
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
- # this should be overridden by concrete adapters
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
- case_sensitive_comparison(attribute, value)
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
- private
546
- def check_version
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 version #:nodoc:
61
- @version ||= Version.new(version_string)
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? #:nodoc:
68
+ def supports_bulk_alter?
69
69
  true
70
70
  end
71
71
 
72
72
  def supports_index_sort_order?
73
- !mariadb? && version >= "8.0.1"
73
+ !mariadb? && database_version >= "8.0.1"
74
74
  end
75
75
 
76
76
  def supports_expression_index?
77
- !mariadb? && version >= "8.0.13"
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? || version >= "5.6.4"
101
+ mariadb? || database_version >= "5.6.4"
102
102
  end
103
103
 
104
104
  def supports_virtual_columns?
105
- mariadb? || version >= "5.7.5"
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
- # Clears the prepared statements cache.
158
- def clear_cache!
178
+ def clear_cache! # :nodoc:
159
179
  reload_type_map
160
- @statements.clear
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 bulk_change_table(table_name, operations) #:nodoc:
283
- sqls = operations.flat_map do |command, args|
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, comment) #:nodoc:
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.key_column_usage
449
- WHERE constraint_name = 'PRIMARY'
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 ordinal_position
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 insert_fixtures_set(fixture_set, tables_to_delete = [])
495
- with_multi_statements do
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
- private
501
- def check_version
502
- if version < "5.5.8"
503
- raise "Your version of MySQL (#{version_string}) is too old. Active Record supports MySQL >= 5.5.8."
504
- end
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
- def combine_multi_statements(total_sql)
508
- total_sql.each_with_object([]) do |sql, total_sql_chunks|
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
- def max_allowed_packet_reached?(current_packet, previous_packet)
520
- if current_packet.bytesize > max_allowed_packet
521
- raise ActiveRecordError, "Fixtures set is too large #{current_packet.bytesize}. Consider increasing the max_allowed_packet variable."
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
- def max_allowed_packet
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 : version >= "5.7.6"
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
- full_version.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
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: