activerecord 6.0.0.beta1 → 6.0.0

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 (156) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +455 -9
  3. data/README.rdoc +3 -1
  4. data/lib/active_record/associations/association.rb +18 -1
  5. data/lib/active_record/associations/builder/association.rb +14 -18
  6. data/lib/active_record/associations/builder/belongs_to.rb +5 -2
  7. data/lib/active_record/associations/builder/collection_association.rb +5 -15
  8. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -1
  9. data/lib/active_record/associations/builder/has_many.rb +2 -0
  10. data/lib/active_record/associations/builder/has_one.rb +35 -1
  11. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  12. data/lib/active_record/associations/collection_association.rb +5 -6
  13. data/lib/active_record/associations/collection_proxy.rb +13 -42
  14. data/lib/active_record/associations/has_many_association.rb +1 -9
  15. data/lib/active_record/associations/has_many_through_association.rb +4 -11
  16. data/lib/active_record/associations/join_dependency/join_association.rb +21 -7
  17. data/lib/active_record/associations/join_dependency.rb +10 -9
  18. data/lib/active_record/associations/preloader/association.rb +37 -34
  19. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  20. data/lib/active_record/associations/preloader.rb +11 -6
  21. data/lib/active_record/associations.rb +3 -2
  22. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  23. data/lib/active_record/attribute_methods/dirty.rb +47 -14
  24. data/lib/active_record/attribute_methods/primary_key.rb +7 -15
  25. data/lib/active_record/attribute_methods/query.rb +2 -3
  26. data/lib/active_record/attribute_methods/read.rb +3 -9
  27. data/lib/active_record/attribute_methods/write.rb +6 -12
  28. data/lib/active_record/attribute_methods.rb +3 -53
  29. data/lib/active_record/attributes.rb +13 -0
  30. data/lib/active_record/autosave_association.rb +15 -5
  31. data/lib/active_record/base.rb +0 -1
  32. data/lib/active_record/callbacks.rb +3 -3
  33. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +124 -23
  34. data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
  35. data/lib/active_record/connection_adapters/abstract/database_statements.rb +101 -70
  36. data/lib/active_record/connection_adapters/abstract/query_cache.rb +11 -5
  37. data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
  38. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -2
  39. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +51 -40
  40. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
  41. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +95 -30
  42. data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
  43. data/lib/active_record/connection_adapters/abstract_adapter.rb +108 -39
  44. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +93 -134
  45. data/lib/active_record/connection_adapters/column.rb +17 -13
  46. data/lib/active_record/connection_adapters/connection_specification.rb +1 -1
  47. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +3 -3
  48. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -7
  49. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  50. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  51. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  52. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +66 -5
  53. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  54. data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -5
  55. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
  56. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +5 -1
  57. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  58. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  59. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  60. data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -3
  61. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
  62. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +98 -89
  63. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +47 -63
  64. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
  65. data/lib/active_record/connection_adapters/postgresql_adapter.rb +91 -24
  66. data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
  67. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  68. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  69. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
  70. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -2
  71. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +69 -118
  72. data/lib/active_record/connection_handling.rb +32 -16
  73. data/lib/active_record/core.rb +27 -20
  74. data/lib/active_record/database_configurations/hash_config.rb +11 -11
  75. data/lib/active_record/database_configurations/url_config.rb +21 -16
  76. data/lib/active_record/database_configurations.rb +99 -50
  77. data/lib/active_record/dynamic_matchers.rb +1 -1
  78. data/lib/active_record/enum.rb +15 -0
  79. data/lib/active_record/errors.rb +18 -13
  80. data/lib/active_record/fixtures.rb +11 -6
  81. data/lib/active_record/gem_version.rb +1 -1
  82. data/lib/active_record/inheritance.rb +1 -1
  83. data/lib/active_record/insert_all.rb +179 -0
  84. data/lib/active_record/integration.rb +13 -1
  85. data/lib/active_record/internal_metadata.rb +5 -1
  86. data/lib/active_record/locking/optimistic.rb +3 -4
  87. data/lib/active_record/log_subscriber.rb +1 -1
  88. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  89. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  90. data/lib/active_record/middleware/database_selector.rb +75 -0
  91. data/lib/active_record/migration/command_recorder.rb +28 -14
  92. data/lib/active_record/migration/compatibility.rb +72 -63
  93. data/lib/active_record/migration.rb +62 -44
  94. data/lib/active_record/persistence.rb +212 -19
  95. data/lib/active_record/querying.rb +18 -14
  96. data/lib/active_record/railtie.rb +9 -1
  97. data/lib/active_record/railties/collection_cache_association_loading.rb +3 -3
  98. data/lib/active_record/railties/databases.rake +124 -25
  99. data/lib/active_record/reflection.rb +18 -32
  100. data/lib/active_record/relation/calculations.rb +40 -44
  101. data/lib/active_record/relation/delegation.rb +23 -31
  102. data/lib/active_record/relation/finder_methods.rb +13 -13
  103. data/lib/active_record/relation/merger.rb +11 -16
  104. data/lib/active_record/relation/query_attribute.rb +5 -3
  105. data/lib/active_record/relation/query_methods.rb +217 -68
  106. data/lib/active_record/relation/spawn_methods.rb +1 -1
  107. data/lib/active_record/relation/where_clause.rb +10 -10
  108. data/lib/active_record/relation.rb +184 -35
  109. data/lib/active_record/sanitization.rb +33 -4
  110. data/lib/active_record/schema.rb +1 -1
  111. data/lib/active_record/schema_dumper.rb +10 -1
  112. data/lib/active_record/schema_migration.rb +1 -1
  113. data/lib/active_record/scoping/default.rb +7 -15
  114. data/lib/active_record/scoping/named.rb +10 -2
  115. data/lib/active_record/scoping.rb +6 -7
  116. data/lib/active_record/statement_cache.rb +2 -2
  117. data/lib/active_record/store.rb +48 -0
  118. data/lib/active_record/table_metadata.rb +9 -13
  119. data/lib/active_record/tasks/database_tasks.rb +109 -6
  120. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -1
  121. data/lib/active_record/test_databases.rb +1 -16
  122. data/lib/active_record/test_fixtures.rb +2 -2
  123. data/lib/active_record/timestamp.rb +35 -19
  124. data/lib/active_record/touch_later.rb +4 -2
  125. data/lib/active_record/transactions.rb +55 -45
  126. data/lib/active_record/type_caster/connection.rb +16 -10
  127. data/lib/active_record/validations/uniqueness.rb +4 -4
  128. data/lib/active_record/validations.rb +1 -0
  129. data/lib/active_record.rb +7 -1
  130. data/lib/arel/insert_manager.rb +3 -3
  131. data/lib/arel/nodes/and.rb +1 -1
  132. data/lib/arel/nodes/case.rb +1 -1
  133. data/lib/arel/nodes/comment.rb +29 -0
  134. data/lib/arel/nodes/select_core.rb +16 -12
  135. data/lib/arel/nodes/unary.rb +1 -0
  136. data/lib/arel/nodes/values_list.rb +2 -17
  137. data/lib/arel/nodes.rb +2 -1
  138. data/lib/arel/select_manager.rb +10 -10
  139. data/lib/arel/visitors/depth_first.rb +7 -2
  140. data/lib/arel/visitors/dot.rb +7 -2
  141. data/lib/arel/visitors/ibm_db.rb +13 -0
  142. data/lib/arel/visitors/informix.rb +6 -0
  143. data/lib/arel/visitors/mssql.rb +15 -1
  144. data/lib/arel/visitors/oracle12.rb +4 -5
  145. data/lib/arel/visitors/postgresql.rb +4 -10
  146. data/lib/arel/visitors/to_sql.rb +107 -131
  147. data/lib/arel/visitors/visitor.rb +9 -5
  148. data/lib/arel.rb +7 -0
  149. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  150. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  151. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  152. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  153. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  154. metadata +17 -13
  155. data/lib/active_record/collection_cache_key.rb +0 -53
  156. data/lib/arel/nodes/values.rb +0 -16
@@ -11,6 +11,7 @@ require "arel/collectors/bind"
11
11
  require "arel/collectors/composite"
12
12
  require "arel/collectors/sql_string"
13
13
  require "arel/collectors/substitute_binds"
14
+ require "concurrent/atomic/thread_local_var"
14
15
 
15
16
  module ActiveRecord
16
17
  module ConnectionAdapters # :nodoc:
@@ -77,11 +78,8 @@ module ActiveRecord
77
78
 
78
79
  SIMPLE_INT = /\A\d+\z/
79
80
 
80
- attr_writer :visitor
81
- deprecate :visitor=
82
-
83
81
  attr_accessor :pool
84
- attr_reader :schema_cache, :visitor, :owner, :logger, :lock, :prepared_statements, :prevent_writes
82
+ attr_reader :visitor, :owner, :logger, :lock
85
83
  alias :in_use? :owner
86
84
 
87
85
  set_callback :checkin, :after, :enable_lazy_transactions!
@@ -105,10 +103,18 @@ module ActiveRecord
105
103
  end
106
104
 
107
105
  def self.build_read_query_regexp(*parts) # :nodoc:
108
- parts = parts.map { |part| /\A\s*#{part}/i }
106
+ parts = parts.map { |part| /\A[\(\s]*#{part}/i }
109
107
  Regexp.union(*parts)
110
108
  end
111
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
+
112
118
  def initialize(connection, logger = nil, config = {}) # :nodoc:
113
119
  super()
114
120
 
@@ -117,26 +123,22 @@ module ActiveRecord
117
123
  @instrumenter = ActiveSupport::Notifications.instrumenter
118
124
  @logger = logger
119
125
  @config = config
120
- @pool = nil
126
+ @pool = ActiveRecord::ConnectionAdapters::NullPool.new
121
127
  @idle_since = Concurrent.monotonic_time
122
- @schema_cache = SchemaCache.new self
123
- @quoted_column_names, @quoted_table_names = {}, {}
124
- @prevent_writes = false
125
128
  @visitor = arel_visitor
129
+ @statements = build_statement_pool
126
130
  @lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
127
131
 
128
132
  if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
129
- @prepared_statements = true
133
+ @prepared_statement_status = Concurrent::ThreadLocalVar.new(true)
130
134
  @visitor.extend(DetermineIfPreparableVisitor)
131
135
  else
132
- @prepared_statements = false
136
+ @prepared_statement_status = Concurrent::ThreadLocalVar.new(false)
133
137
  end
134
138
 
135
139
  @advisory_locks_enabled = self.class.type_cast_config_to_boolean(
136
140
  config.fetch(:advisory_locks, true)
137
141
  )
138
-
139
- check_version
140
142
  end
141
143
 
142
144
  def replica?
@@ -148,19 +150,7 @@ module ActiveRecord
148
150
  # Returns true if the connection is a replica, or if +prevent_writes+
149
151
  # is set to true.
150
152
  def preventing_writes?
151
- replica? || prevent_writes
152
- end
153
-
154
- # Prevent writing to the database regardless of role.
155
- #
156
- # In some cases you may want to prevent writes to the database
157
- # even if you are on a database that can write. `while_preventing_writes`
158
- # will prevent writes to the database for the duration of the block.
159
- def while_preventing_writes
160
- original, @prevent_writes = @prevent_writes, true
161
- yield
162
- ensure
163
- @prevent_writes = original
153
+ replica? || ActiveRecord::Base.connection_handler.prevent_writes
164
154
  end
165
155
 
166
156
  def migrations_paths # :nodoc:
@@ -168,14 +158,36 @@ module ActiveRecord
168
158
  end
169
159
 
170
160
  def migration_context # :nodoc:
171
- 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_statement_status.value
172
181
  end
173
182
 
174
183
  class Version
175
184
  include Comparable
176
185
 
177
- def initialize(version_string)
186
+ attr_reader :full_version_string
187
+
188
+ def initialize(version_string, full_version_string = nil)
178
189
  @version = version_string.split(".").map(&:to_i)
190
+ @full_version_string = full_version_string
179
191
  end
180
192
 
181
193
  def <=>(version_string)
@@ -207,9 +219,13 @@ module ActiveRecord
207
219
  @owner = Thread.current
208
220
  end
209
221
 
222
+ def schema_cache
223
+ @pool.get_schema_cache(self)
224
+ end
225
+
210
226
  def schema_cache=(cache)
211
227
  cache.connection = self
212
- @schema_cache = cache
228
+ @pool.set_schema_cache(cache)
213
229
  end
214
230
 
215
231
  # this method must only be called while holding connection pool's mutex
@@ -248,10 +264,7 @@ module ActiveRecord
248
264
  end
249
265
 
250
266
  def unprepared_statement
251
- old_prepared_statements, @prepared_statements = @prepared_statements, false
252
- yield
253
- ensure
254
- @prepared_statements = old_prepared_statements
267
+ @prepared_statement_status.bind(false) { yield }
255
268
  end
256
269
 
257
270
  # Returns the human-readable name of the adapter. Use mixed case - one
@@ -260,6 +273,11 @@ module ActiveRecord
260
273
  self.class::ADAPTER_NAME
261
274
  end
262
275
 
276
+ # Does the database for this adapter exist?
277
+ def self.database_exists?(config)
278
+ raise NotImplementedError
279
+ end
280
+
263
281
  # Does this adapter support DDL rollbacks in transactions? That is, would
264
282
  # CREATE TABLE or ALTER TABLE get rolled back by a transaction?
265
283
  def supports_ddl_transactions?
@@ -338,6 +356,7 @@ module ActiveRecord
338
356
  def supports_foreign_keys_in_create?
339
357
  supports_foreign_keys?
340
358
  end
359
+ deprecate :supports_foreign_keys_in_create?
341
360
 
342
361
  # Does this adapter support views?
343
362
  def supports_views?
@@ -385,10 +404,31 @@ module ActiveRecord
385
404
  false
386
405
  end
387
406
 
407
+ # Does this adapter support optimizer hints?
408
+ def supports_optimizer_hints?
409
+ false
410
+ end
411
+
388
412
  def supports_lazy_transactions?
389
413
  false
390
414
  end
391
415
 
416
+ def supports_insert_returning?
417
+ false
418
+ end
419
+
420
+ def supports_insert_on_duplicate_skip?
421
+ false
422
+ end
423
+
424
+ def supports_insert_on_duplicate_update?
425
+ false
426
+ end
427
+
428
+ def supports_insert_conflict_target?
429
+ false
430
+ end
431
+
392
432
  # This is meant to be implemented by the adapters that support extensions
393
433
  def disable_extension(name)
394
434
  end
@@ -466,6 +506,9 @@ module ActiveRecord
466
506
  #
467
507
  # Prevent @connection's finalizer from touching the socket, or
468
508
  # otherwise communicating with its server, when it is collected.
509
+ if schema_cache.connection == self
510
+ schema_cache.connection = nil
511
+ end
469
512
  end
470
513
 
471
514
  # Reset the state of this connection, directing the DBMS to clear
@@ -478,11 +521,9 @@ module ActiveRecord
478
521
  # this should be overridden by concrete adapters
479
522
  end
480
523
 
481
- ###
482
- # Clear any caching the database adapter may be doing, for example
483
- # clearing the prepared statement cache. This is database specific.
524
+ # Clear any caching the database adapter may be doing.
484
525
  def clear_cache!
485
- # this should be overridden by concrete adapters
526
+ @lock.synchronize { @statements.clear } if @statements
486
527
  end
487
528
 
488
529
  # Returns true if its required to reload the connection between requests for development mode.
@@ -508,6 +549,10 @@ module ActiveRecord
508
549
  @connection
509
550
  end
510
551
 
552
+ def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
553
+ attribute.eq(value)
554
+ end
555
+
511
556
  def case_sensitive_comparison(attribute, value) # :nodoc:
512
557
  attribute.eq(value)
513
558
  end
@@ -540,10 +585,31 @@ module ActiveRecord
540
585
  index.using.nil?
541
586
  end
542
587
 
543
- private
544
- def check_version
588
+ # Called by ActiveRecord::InsertAll,
589
+ # Passed an instance of ActiveRecord::InsertAll::Builder,
590
+ # This method implements standard bulk inserts for all databases, but
591
+ # should be overridden by adapters to implement common features with
592
+ # non-standard syntax like handling duplicates or returning values.
593
+ def build_insert_sql(insert) # :nodoc:
594
+ if insert.skip_duplicates? || insert.update_duplicates?
595
+ raise NotImplementedError, "#{self.class} should define `build_insert_sql` to implement adapter-specific logic for handling duplicates during INSERT"
545
596
  end
546
597
 
598
+ "INSERT #{insert.into} #{insert.values_list}"
599
+ end
600
+
601
+ def get_database_version # :nodoc:
602
+ end
603
+
604
+ def database_version # :nodoc:
605
+ schema_cache.database_version
606
+ end
607
+
608
+ def check_version # :nodoc:
609
+ end
610
+
611
+ private
612
+
547
613
  def type_map
548
614
  @type_map ||= Type::TypeMap.new.tap do |mapping|
549
615
  initialize_type_map(mapping)
@@ -687,6 +753,9 @@ module ActiveRecord
687
753
  def arel_visitor
688
754
  Arel::Visitors::ToSql.new(self)
689
755
  end
756
+
757
+ def build_statement_pool
758
+ end
690
759
  end
691
760
  end
692
761
  end
@@ -29,7 +29,7 @@ module ActiveRecord
29
29
  NATIVE_DATABASE_TYPES = {
30
30
  primary_key: "bigint auto_increment PRIMARY KEY",
31
31
  string: { name: "varchar", limit: 255 },
32
- text: { name: "text", limit: 65535 },
32
+ text: { name: "text" },
33
33
  integer: { name: "int", limit: 4 },
34
34
  float: { name: "float", limit: 24 },
35
35
  decimal: { name: "decimal" },
@@ -37,7 +37,8 @@ module ActiveRecord
37
37
  timestamp: { name: "timestamp" },
38
38
  time: { name: "time" },
39
39
  date: { name: "date" },
40
- binary: { name: "blob", limit: 65535 },
40
+ binary: { name: "blob" },
41
+ blob: { name: "blob" },
41
42
  boolean: { name: "tinyint", limit: 1 },
42
43
  json: { name: "json" },
43
44
  }
@@ -52,28 +53,28 @@ module ActiveRecord
52
53
 
53
54
  def initialize(connection, logger, connection_options, config)
54
55
  super(connection, logger, config)
55
-
56
- @statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
57
56
  end
58
57
 
59
- def version #:nodoc:
60
- @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)
61
62
  end
62
63
 
63
64
  def mariadb? # :nodoc:
64
65
  /mariadb/i.match?(full_version)
65
66
  end
66
67
 
67
- def supports_bulk_alter? #:nodoc:
68
+ def supports_bulk_alter?
68
69
  true
69
70
  end
70
71
 
71
72
  def supports_index_sort_order?
72
- !mariadb? && version >= "8.0.1"
73
+ !mariadb? && database_version >= "8.0.1"
73
74
  end
74
75
 
75
76
  def supports_expression_index?
76
- !mariadb? && version >= "8.0.13"
77
+ !mariadb? && database_version >= "8.0.13"
77
78
  end
78
79
 
79
80
  def supports_transaction_isolation?
@@ -97,17 +98,30 @@ module ActiveRecord
97
98
  end
98
99
 
99
100
  def supports_datetime_with_precision?
100
- mariadb? || version >= "5.6.4"
101
+ mariadb? || database_version >= "5.6.4"
101
102
  end
102
103
 
103
104
  def supports_virtual_columns?
104
- 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"
105
111
  end
106
112
 
107
113
  def supports_advisory_locks?
108
114
  true
109
115
  end
110
116
 
117
+ def supports_insert_on_duplicate_skip?
118
+ true
119
+ end
120
+
121
+ def supports_insert_on_duplicate_update?
122
+ true
123
+ end
124
+
111
125
  def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
112
126
  query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
113
127
  end
@@ -153,10 +167,9 @@ module ActiveRecord
153
167
 
154
168
  # CONNECTION MANAGEMENT ====================================
155
169
 
156
- # Clears the prepared statements cache.
157
- def clear_cache!
170
+ def clear_cache! # :nodoc:
158
171
  reload_type_map
159
- @statements.clear
172
+ super
160
173
  end
161
174
 
162
175
  #--
@@ -165,9 +178,9 @@ module ActiveRecord
165
178
 
166
179
  def explain(arel, binds = [])
167
180
  sql = "EXPLAIN #{to_sql(arel, binds)}"
168
- start = Time.now
181
+ start = Concurrent.monotonic_time
169
182
  result = exec_query(sql, "EXPLAIN", binds)
170
- elapsed = Time.now - start
183
+ elapsed = Concurrent.monotonic_time - start
171
184
 
172
185
  MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
173
186
  end
@@ -263,10 +276,6 @@ module ActiveRecord
263
276
  show_variable "collation_database"
264
277
  end
265
278
 
266
- def truncate(table_name, name = nil)
267
- execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
268
- end
269
-
270
279
  def table_comment(table_name) # :nodoc:
271
280
  scope = quoted_scope(table_name)
272
281
 
@@ -278,22 +287,8 @@ module ActiveRecord
278
287
  SQL
279
288
  end
280
289
 
281
- def bulk_change_table(table_name, operations) #:nodoc:
282
- sqls = operations.flat_map do |command, args|
283
- table, arguments = args.shift, args
284
- method = :"#{command}_for_alter"
285
-
286
- if respond_to?(method, true)
287
- send(method, table, *arguments)
288
- else
289
- raise "Unknown method called : #{method}(#{arguments.inspect})"
290
- end
291
- end.join(", ")
292
-
293
- execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}")
294
- end
295
-
296
- def change_table_comment(table_name, comment) #:nodoc:
290
+ def change_table_comment(table_name, comment_or_changes) # :nodoc:
291
+ comment = extract_new_comment_value(comment_or_changes)
297
292
  comment = "" if comment.nil?
298
293
  execute("ALTER TABLE #{quote_table_name(table_name)} COMMENT #{quote(comment)}")
299
294
  end
@@ -349,7 +344,8 @@ module ActiveRecord
349
344
  change_column table_name, column_name, nil, null: null
350
345
  end
351
346
 
352
- def change_column_comment(table_name, column_name, comment) #:nodoc:
347
+ def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
348
+ comment = extract_new_comment_value(comment_or_changes)
353
349
  change_column table_name, column_name, nil, comment: comment
354
350
  end
355
351
 
@@ -430,30 +426,6 @@ module ActiveRecord
430
426
  table_options
431
427
  end
432
428
 
433
- # Maps logical Rails types to MySQL-specific data types.
434
- def type_to_sql(type, limit: nil, precision: nil, scale: nil, unsigned: nil, **) # :nodoc:
435
- sql = \
436
- case type.to_s
437
- when "integer"
438
- integer_to_sql(limit)
439
- when "text"
440
- text_to_sql(limit)
441
- when "blob"
442
- binary_to_sql(limit)
443
- when "binary"
444
- if (0..0xfff) === limit
445
- "varbinary(#{limit})"
446
- else
447
- binary_to_sql(limit)
448
- end
449
- else
450
- super
451
- end
452
-
453
- sql = "#{sql} unsigned" if unsigned && type != :primary_key
454
- sql
455
- end
456
-
457
429
  # SHOW VARIABLES LIKE 'name'
458
430
  def show_variable(name)
459
431
  query_value("SELECT @@#{name}", "SCHEMA")
@@ -476,6 +448,21 @@ module ActiveRecord
476
448
  SQL
477
449
  end
478
450
 
451
+ def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
452
+ column = column_for_attribute(attribute)
453
+
454
+ if column.collation && !column.case_sensitive? && !value.nil?
455
+ ActiveSupport::Deprecation.warn(<<~MSG.squish)
456
+ Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1.
457
+ To continue case sensitive comparison on the :#{attribute.name} attribute in #{klass} model,
458
+ pass `case_sensitive: true` option explicitly to the uniqueness validator.
459
+ MSG
460
+ attribute.eq(Arel::Nodes::Bin.new(value))
461
+ else
462
+ super
463
+ end
464
+ end
465
+
479
466
  def case_sensitive_comparison(attribute, value) # :nodoc:
480
467
  column = column_for_attribute(attribute)
481
468
 
@@ -514,45 +501,27 @@ module ActiveRecord
514
501
  index.using == :btree || super
515
502
  end
516
503
 
517
- def insert_fixtures_set(fixture_set, tables_to_delete = [])
518
- with_multi_statements do
519
- super { discard_remaining_results }
520
- end
521
- end
504
+ def build_insert_sql(insert) # :nodoc:
505
+ sql = +"INSERT #{insert.into} #{insert.values_list}"
522
506
 
523
- private
524
- def check_version
525
- if version < "5.5.8"
526
- raise "Your version of MySQL (#{version_string}) is too old. Active Record supports MySQL >= 5.5.8."
527
- end
507
+ if insert.skip_duplicates?
508
+ no_op_column = quote_column_name(insert.keys.first)
509
+ sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
510
+ elsif insert.update_duplicates?
511
+ sql << " ON DUPLICATE KEY UPDATE "
512
+ sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
528
513
  end
529
514
 
530
- def combine_multi_statements(total_sql)
531
- total_sql.each_with_object([]) do |sql, total_sql_chunks|
532
- previous_packet = total_sql_chunks.last
533
- sql << ";\n"
534
- if max_allowed_packet_reached?(sql, previous_packet) || total_sql_chunks.empty?
535
- total_sql_chunks << sql
536
- else
537
- previous_packet << sql
538
- end
539
- end
540
- end
515
+ sql
516
+ end
541
517
 
542
- def max_allowed_packet_reached?(current_packet, previous_packet)
543
- if current_packet.bytesize > max_allowed_packet
544
- raise ActiveRecordError, "Fixtures set is too large #{current_packet.bytesize}. Consider increasing the max_allowed_packet variable."
545
- elsif previous_packet.nil?
546
- false
547
- else
548
- (current_packet.bytesize + previous_packet.bytesize) > max_allowed_packet
549
- end
518
+ def check_version # :nodoc:
519
+ if database_version < "5.5.8"
520
+ raise "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
550
521
  end
522
+ end
551
523
 
552
- def max_allowed_packet
553
- bytes_margin = 2
554
- @max_allowed_packet ||= (show_variable("max_allowed_packet") - bytes_margin)
555
- end
524
+ private
556
525
 
557
526
  def initialize_type_map(m = type_map)
558
527
  super
@@ -627,6 +596,7 @@ module ActiveRecord
627
596
  ER_LOCK_WAIT_TIMEOUT = 1205
628
597
  ER_QUERY_INTERRUPTED = 1317
629
598
  ER_QUERY_TIMEOUT = 3024
599
+ ER_FK_INCOMPATIBLE_COLUMNS = 3780
630
600
 
631
601
  def translate_exception(exception, message:, sql:, binds:)
632
602
  case error_number(exception)
@@ -634,7 +604,7 @@ module ActiveRecord
634
604
  RecordNotUnique.new(message, sql: sql, binds: binds)
635
605
  when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
636
606
  InvalidForeignKey.new(message, sql: sql, binds: binds)
637
- when ER_CANNOT_ADD_FOREIGN
607
+ when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
638
608
  mismatched_foreign_key(message, sql: sql, binds: binds)
639
609
  when ER_CANNOT_CREATE_TABLE
640
610
  if message.include?("errno: 150")
@@ -708,6 +678,12 @@ module ActiveRecord
708
678
  end
709
679
 
710
680
  def add_timestamps_for_alter(table_name, options = {})
681
+ options[:null] = false if options[:null].nil?
682
+
683
+ if !options.key?(:precision) && supports_datetime_with_precision?
684
+ options[:precision] = 6
685
+ end
686
+
711
687
  [add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
712
688
  end
713
689
 
@@ -716,7 +692,7 @@ module ActiveRecord
716
692
  end
717
693
 
718
694
  def supports_rename_index?
719
- mariadb? ? false : version >= "5.7.6"
695
+ mariadb? ? false : database_version >= "5.7.6"
720
696
  end
721
697
 
722
698
  def configure_connection
@@ -786,53 +762,36 @@ module ActiveRecord
786
762
  Arel::Visitors::MySQL.new(self)
787
763
  end
788
764
 
765
+ def build_statement_pool
766
+ StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
767
+ end
768
+
789
769
  def mismatched_foreign_key(message, sql:, binds:)
790
- parts = sql.scan(/`(\w+)`[ $)]/).flatten
791
- MismatchedForeignKey.new(
792
- self,
770
+ match = %r/
771
+ (?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
772
+ FOREIGN\s+KEY\s*\(`?(?<foreign_key>\w+)`?\)\s*
773
+ REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
774
+ /xmi.match(sql)
775
+
776
+ options = {
793
777
  message: message,
794
778
  sql: sql,
795
779
  binds: binds,
796
- table: parts[0],
797
- foreign_key: parts[1],
798
- target_table: parts[2],
799
- primary_key: parts[3],
800
- )
801
- end
802
-
803
- def integer_to_sql(limit) # :nodoc:
804
- case limit
805
- when 1; "tinyint"
806
- when 2; "smallint"
807
- when 3; "mediumint"
808
- when nil, 4; "int"
809
- when 5..8; "bigint"
810
- else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a decimal with scale 0 instead.")
811
- end
812
- end
780
+ }
813
781
 
814
- def text_to_sql(limit) # :nodoc:
815
- case limit
816
- when 0..0xff; "tinytext"
817
- when nil, 0x100..0xffff; "text"
818
- when 0x10000..0xffffff; "mediumtext"
819
- when 0x1000000..0xffffffff; "longtext"
820
- else raise(ActiveRecordError, "No text type has byte length #{limit}")
782
+ if match
783
+ options[:table] = match[:table]
784
+ options[:foreign_key] = match[:foreign_key]
785
+ options[:target_table] = match[:target_table]
786
+ options[:primary_key] = match[:primary_key]
787
+ options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
821
788
  end
822
- end
823
789
 
824
- def binary_to_sql(limit) # :nodoc:
825
- case limit
826
- when 0..0xff; "tinyblob"
827
- when nil, 0x100..0xffff; "blob"
828
- when 0x10000..0xffffff; "mediumblob"
829
- when 0x1000000..0xffffffff; "longblob"
830
- else raise(ActiveRecordError, "No binary type has byte length #{limit}")
831
- end
790
+ MismatchedForeignKey.new(options)
832
791
  end
833
792
 
834
- def version_string
835
- full_version.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
793
+ def version_string(full_version_string)
794
+ full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
836
795
  end
837
796
 
838
797
  class MysqlString < Type::String # :nodoc: