activerecord 6.1.3.2 → 7.0.0.alpha2

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 (229) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +734 -1058
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +0 -10
  7. data/lib/active_record/associations/association.rb +35 -7
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +16 -6
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +8 -2
  12. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  13. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  14. data/lib/active_record/associations/builder/has_many.rb +3 -2
  15. data/lib/active_record/associations/builder/has_one.rb +2 -1
  16. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  17. data/lib/active_record/associations/collection_association.rb +24 -25
  18. data/lib/active_record/associations/collection_proxy.rb +8 -3
  19. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  20. data/lib/active_record/associations/has_many_association.rb +1 -1
  21. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  22. data/lib/active_record/associations/has_one_association.rb +10 -7
  23. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  24. data/lib/active_record/associations/preloader/association.rb +161 -49
  25. data/lib/active_record/associations/preloader/batch.rb +51 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +37 -11
  28. data/lib/active_record/associations/preloader.rb +46 -110
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +1 -1
  31. data/lib/active_record/associations.rb +76 -81
  32. data/lib/active_record/asynchronous_queries_tracker.rb +57 -0
  33. data/lib/active_record/attribute_assignment.rb +1 -1
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  35. data/lib/active_record/attribute_methods/dirty.rb +41 -16
  36. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  37. data/lib/active_record/attribute_methods/query.rb +2 -2
  38. data/lib/active_record/attribute_methods/read.rb +7 -5
  39. data/lib/active_record/attribute_methods/serialization.rb +66 -12
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +6 -9
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +3 -18
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +2 -2
  47. data/lib/active_record/coders/yaml_column.rb +11 -1
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -558
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -7
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -18
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -9
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +115 -69
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
  61. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +6 -2
  62. data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -21
  63. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
  64. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -0
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  66. data/lib/active_record/connection_adapters/pool_config.rb +1 -3
  67. data/lib/active_record/connection_adapters/pool_manager.rb +5 -1
  68. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
  69. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  72. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  73. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  76. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  77. data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -6
  78. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  79. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
  80. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
  81. data/lib/active_record/connection_adapters/postgresql_adapter.rb +157 -100
  82. data/lib/active_record/connection_adapters/schema_cache.rb +35 -4
  83. data/lib/active_record/connection_adapters/sql_type_metadata.rb +0 -2
  84. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -17
  85. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
  86. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
  87. data/lib/active_record/connection_adapters.rb +8 -5
  88. data/lib/active_record/connection_handling.rb +20 -38
  89. data/lib/active_record/core.rb +129 -117
  90. data/lib/active_record/database_configurations/database_config.rb +12 -0
  91. data/lib/active_record/database_configurations/hash_config.rb +27 -1
  92. data/lib/active_record/database_configurations/url_config.rb +2 -2
  93. data/lib/active_record/database_configurations.rb +18 -9
  94. data/lib/active_record/delegated_type.rb +33 -11
  95. data/lib/active_record/destroy_association_async_job.rb +1 -1
  96. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  97. data/lib/active_record/dynamic_matchers.rb +1 -1
  98. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  99. data/lib/active_record/encryption/cipher.rb +53 -0
  100. data/lib/active_record/encryption/config.rb +44 -0
  101. data/lib/active_record/encryption/configurable.rb +61 -0
  102. data/lib/active_record/encryption/context.rb +35 -0
  103. data/lib/active_record/encryption/contexts.rb +72 -0
  104. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  105. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  106. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  107. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  108. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  109. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  110. data/lib/active_record/encryption/encryptor.rb +155 -0
  111. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  112. data/lib/active_record/encryption/errors.rb +15 -0
  113. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  114. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
  115. data/lib/active_record/encryption/key.rb +28 -0
  116. data/lib/active_record/encryption/key_generator.rb +42 -0
  117. data/lib/active_record/encryption/key_provider.rb +46 -0
  118. data/lib/active_record/encryption/message.rb +33 -0
  119. data/lib/active_record/encryption/message_serializer.rb +80 -0
  120. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  121. data/lib/active_record/encryption/properties.rb +76 -0
  122. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  123. data/lib/active_record/encryption/scheme.rb +99 -0
  124. data/lib/active_record/encryption.rb +55 -0
  125. data/lib/active_record/enum.rb +44 -46
  126. data/lib/active_record/errors.rb +66 -3
  127. data/lib/active_record/fixture_set/file.rb +15 -1
  128. data/lib/active_record/fixture_set/table_row.rb +40 -5
  129. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  130. data/lib/active_record/fixtures.rb +16 -11
  131. data/lib/active_record/future_result.rb +139 -0
  132. data/lib/active_record/gem_version.rb +4 -4
  133. data/lib/active_record/inheritance.rb +55 -17
  134. data/lib/active_record/insert_all.rb +39 -6
  135. data/lib/active_record/integration.rb +1 -1
  136. data/lib/active_record/internal_metadata.rb +3 -5
  137. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  138. data/lib/active_record/locking/optimistic.rb +10 -9
  139. data/lib/active_record/log_subscriber.rb +6 -2
  140. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  141. data/lib/active_record/middleware/database_selector.rb +8 -3
  142. data/lib/active_record/migration/command_recorder.rb +4 -4
  143. data/lib/active_record/migration/compatibility.rb +83 -1
  144. data/lib/active_record/migration/join_table.rb +1 -1
  145. data/lib/active_record/migration.rb +109 -79
  146. data/lib/active_record/model_schema.rb +46 -32
  147. data/lib/active_record/nested_attributes.rb +3 -3
  148. data/lib/active_record/no_touching.rb +2 -2
  149. data/lib/active_record/null_relation.rb +2 -6
  150. data/lib/active_record/persistence.rb +134 -45
  151. data/lib/active_record/query_cache.rb +2 -2
  152. data/lib/active_record/query_logs.rb +203 -0
  153. data/lib/active_record/querying.rb +15 -5
  154. data/lib/active_record/railtie.rb +117 -17
  155. data/lib/active_record/railties/controller_runtime.rb +1 -1
  156. data/lib/active_record/railties/databases.rake +83 -58
  157. data/lib/active_record/readonly_attributes.rb +11 -0
  158. data/lib/active_record/reflection.rb +45 -44
  159. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  160. data/lib/active_record/relation/batches.rb +3 -3
  161. data/lib/active_record/relation/calculations.rb +42 -25
  162. data/lib/active_record/relation/delegation.rb +6 -6
  163. data/lib/active_record/relation/finder_methods.rb +32 -23
  164. data/lib/active_record/relation/merger.rb +20 -13
  165. data/lib/active_record/relation/predicate_builder.rb +1 -6
  166. data/lib/active_record/relation/query_attribute.rb +5 -11
  167. data/lib/active_record/relation/query_methods.rb +233 -50
  168. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  169. data/lib/active_record/relation/spawn_methods.rb +2 -2
  170. data/lib/active_record/relation/where_clause.rb +22 -15
  171. data/lib/active_record/relation.rb +170 -87
  172. data/lib/active_record/result.rb +17 -2
  173. data/lib/active_record/runtime_registry.rb +2 -4
  174. data/lib/active_record/sanitization.rb +11 -7
  175. data/lib/active_record/schema_dumper.rb +3 -3
  176. data/lib/active_record/schema_migration.rb +0 -4
  177. data/lib/active_record/scoping/default.rb +62 -15
  178. data/lib/active_record/scoping/named.rb +3 -11
  179. data/lib/active_record/scoping.rb +40 -22
  180. data/lib/active_record/serialization.rb +1 -1
  181. data/lib/active_record/signed_id.rb +1 -1
  182. data/lib/active_record/statement_cache.rb +2 -2
  183. data/lib/active_record/tasks/database_tasks.rb +107 -23
  184. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  185. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
  186. data/lib/active_record/test_databases.rb +1 -1
  187. data/lib/active_record/test_fixtures.rb +45 -4
  188. data/lib/active_record/timestamp.rb +3 -4
  189. data/lib/active_record/transactions.rb +9 -14
  190. data/lib/active_record/translation.rb +2 -2
  191. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  192. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  193. data/lib/active_record/type/internal/timezone.rb +2 -2
  194. data/lib/active_record/type/serialized.rb +1 -1
  195. data/lib/active_record/type/type_map.rb +17 -20
  196. data/lib/active_record/type.rb +1 -2
  197. data/lib/active_record/validations/associated.rb +1 -1
  198. data/lib/active_record/validations/numericality.rb +1 -1
  199. data/lib/active_record.rb +170 -2
  200. data/lib/arel/attributes/attribute.rb +0 -8
  201. data/lib/arel/collectors/bind.rb +2 -2
  202. data/lib/arel/collectors/composite.rb +3 -3
  203. data/lib/arel/collectors/sql_string.rb +1 -1
  204. data/lib/arel/collectors/substitute_binds.rb +1 -1
  205. data/lib/arel/crud.rb +18 -22
  206. data/lib/arel/delete_manager.rb +2 -4
  207. data/lib/arel/insert_manager.rb +2 -3
  208. data/lib/arel/nodes/casted.rb +1 -1
  209. data/lib/arel/nodes/delete_statement.rb +8 -13
  210. data/lib/arel/nodes/homogeneous_in.rb +4 -0
  211. data/lib/arel/nodes/insert_statement.rb +2 -2
  212. data/lib/arel/nodes/select_core.rb +2 -2
  213. data/lib/arel/nodes/select_statement.rb +2 -2
  214. data/lib/arel/nodes/update_statement.rb +3 -2
  215. data/lib/arel/predications.rb +3 -3
  216. data/lib/arel/select_manager.rb +10 -4
  217. data/lib/arel/table.rb +0 -1
  218. data/lib/arel/tree_manager.rb +0 -12
  219. data/lib/arel/update_manager.rb +2 -4
  220. data/lib/arel/visitors/dot.rb +80 -90
  221. data/lib/arel/visitors/mysql.rb +6 -1
  222. data/lib/arel/visitors/postgresql.rb +0 -10
  223. data/lib/arel/visitors/to_sql.rb +44 -3
  224. data/lib/arel.rb +1 -1
  225. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  226. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  227. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  228. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  229. metadata +55 -16
@@ -33,6 +33,10 @@ module ActiveRecord
33
33
  @state == :fully_rolledback
34
34
  end
35
35
 
36
+ def invalidated?
37
+ @state == :invalidated
38
+ end
39
+
36
40
  def fully_completed?
37
41
  completed?
38
42
  end
@@ -51,6 +55,11 @@ module ActiveRecord
51
55
  @state = :fully_rolledback
52
56
  end
53
57
 
58
+ def invalidate!
59
+ @children&.each { |c| c.invalidate! }
60
+ @state = :invalidated
61
+ end
62
+
54
63
  def commit!
55
64
  @state = :committed
56
65
  end
@@ -64,7 +73,7 @@ module ActiveRecord
64
73
  end
65
74
  end
66
75
 
67
- class NullTransaction #:nodoc:
76
+ class NullTransaction # :nodoc:
68
77
  def initialize; end
69
78
  def state; end
70
79
  def closed?; true; end
@@ -73,7 +82,7 @@ module ActiveRecord
73
82
  def add_record(record, _ = true); end
74
83
  end
75
84
 
76
- class Transaction #:nodoc:
85
+ class Transaction # :nodoc:
77
86
  attr_reader :connection, :state, :savepoint_name, :isolation_level
78
87
  attr_accessor :written
79
88
 
@@ -212,7 +221,7 @@ module ActiveRecord
212
221
  end
213
222
  end
214
223
 
215
- class TransactionManager #:nodoc:
224
+ class TransactionManager # :nodoc:
216
225
  def initialize(connection)
217
226
  @stack = []
218
227
  @connection = connection
@@ -299,7 +308,7 @@ module ActiveRecord
299
308
  def rollback_transaction(transaction = nil)
300
309
  @connection.lock.synchronize do
301
310
  transaction ||= @stack.pop
302
- transaction.rollback
311
+ transaction.rollback unless transaction.state.invalidated?
303
312
  transaction.rollback_records
304
313
  end
305
314
  end
@@ -312,15 +321,17 @@ module ActiveRecord
312
321
  ret
313
322
  rescue Exception => error
314
323
  if transaction
324
+ transaction.state.invalidate! if error.is_a? ActiveRecord::TransactionRollbackError
315
325
  rollback_transaction
316
326
  after_failure_actions(transaction, error)
317
327
  end
328
+
318
329
  raise
319
330
  ensure
320
331
  if transaction
321
332
  if error
322
- # @connection still holds an open transaction, so we must not
323
- # put it back in the pool for reuse
333
+ # @connection still holds an open or invalid transaction, so we must not
334
+ # put it back in the pool for reuse.
324
335
  @connection.throw_away! unless transaction.state.rolledback?
325
336
  else
326
337
  if Thread.current.status == "aborting"
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "set"
4
- require "active_record/connection_adapters/schema_cache"
5
4
  require "active_record/connection_adapters/sql_type_metadata"
6
5
  require "active_record/connection_adapters/abstract/schema_dumper"
7
6
  require "active_record/connection_adapters/abstract/schema_creation"
@@ -37,7 +36,7 @@ module ActiveRecord
37
36
  include Savepoints
38
37
 
39
38
  SIMPLE_INT = /\A\d+\z/
40
- COMMENT_REGEX = %r{(?:\-\-.*\n)*|/\*(?:[^\*]|\*[^/])*\*/}m
39
+ COMMENT_REGEX = %r{(?:--.*\n)*|/\*(?:[^*]|\*[^/])*\*/}m
41
40
 
42
41
  attr_accessor :pool
43
42
  attr_reader :visitor, :owner, :logger, :lock
@@ -69,7 +68,7 @@ module ActiveRecord
69
68
  def self.build_read_query_regexp(*parts) # :nodoc:
70
69
  parts += DEFAULT_READ_QUERY
71
70
  parts = parts.map { |part| /#{part}/i }
72
- /\A(?:[\(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
71
+ /\A(?:[(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
73
72
  end
74
73
 
75
74
  def self.quoted_column_names # :nodoc:
@@ -103,6 +102,25 @@ module ActiveRecord
103
102
  )
104
103
  end
105
104
 
105
+ EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
106
+ EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze # :nodoc:
107
+ private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
108
+ def with_instrumenter(instrumenter, &block) # :nodoc:
109
+ Thread.handle_interrupt(EXCEPTION_NEVER) do
110
+ previous_instrumenter = @instrumenter
111
+ @instrumenter = instrumenter
112
+ Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
113
+ ensure
114
+ @instrumenter = previous_instrumenter
115
+ end
116
+ end
117
+
118
+ def check_if_write_query(sql) # :nodoc:
119
+ if preventing_writes? && write_query?(sql)
120
+ raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
121
+ end
122
+ end
123
+
106
124
  def replica?
107
125
  @config[:replica] || false
108
126
  end
@@ -122,7 +140,7 @@ module ActiveRecord
122
140
  # will return true based on +current_preventing_writes+.
123
141
  def preventing_writes?
124
142
  return true if replica?
125
- return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord::Base.legacy_connection_handling
143
+ return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord.legacy_connection_handling
126
144
  return false if connection_klass.nil?
127
145
 
128
146
  connection_klass.current_preventing_writes
@@ -154,9 +172,10 @@ module ActiveRecord
154
172
  end
155
173
  end
156
174
 
157
- def prepared_statements
175
+ def prepared_statements?
158
176
  @prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
159
177
  end
178
+ alias :prepared_statements :prepared_statements?
160
179
 
161
180
  def prepared_statements_disabled_cache # :nodoc:
162
181
  Thread.current[:ar_prepared_statements_disabled_cache] ||= Set.new
@@ -250,7 +269,7 @@ module ActiveRecord
250
269
  end
251
270
 
252
271
  def unprepared_statement
253
- cache = prepared_statements_disabled_cache.add(object_id) if @prepared_statements
272
+ cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements
254
273
  yield
255
274
  ensure
256
275
  cache&.delete(object_id)
@@ -418,6 +437,15 @@ module ActiveRecord
418
437
  false
419
438
  end
420
439
 
440
+ def supports_concurrent_connections?
441
+ true
442
+ end
443
+
444
+ def async_enabled? # :nodoc:
445
+ supports_concurrent_connections? &&
446
+ !ActiveRecord.async_query_executor.nil? && !pool.async_executor.nil?
447
+ end
448
+
421
449
  # This is meant to be implemented by the adapters that support extensions
422
450
  def disable_extension(name)
423
451
  end
@@ -461,6 +489,11 @@ module ActiveRecord
461
489
  yield
462
490
  end
463
491
 
492
+ # Override to check all foreign key constraints in a database.
493
+ def all_foreign_keys_valid?
494
+ true
495
+ end
496
+
464
497
  # CONNECTION MANAGEMENT ====================================
465
498
 
466
499
  # Checks whether the connection to the database is still active. This includes
@@ -599,78 +632,85 @@ module ActiveRecord
599
632
  def check_version # :nodoc:
600
633
  end
601
634
 
602
- private
603
- def type_map
604
- @type_map ||= Type::TypeMap.new.tap do |mapping|
605
- initialize_type_map(mapping)
606
- end
635
+ def field_ordered_value(column, values) # :nodoc:
636
+ node = Arel::Nodes::Case.new(column)
637
+ values.each.with_index(1) do |value, order|
638
+ node.when(value).then(order)
607
639
  end
608
640
 
609
- def initialize_type_map(m = type_map)
610
- register_class_with_limit m, %r(boolean)i, Type::Boolean
611
- register_class_with_limit m, %r(char)i, Type::String
612
- register_class_with_limit m, %r(binary)i, Type::Binary
613
- register_class_with_limit m, %r(text)i, Type::Text
614
- register_class_with_precision m, %r(date)i, Type::Date
615
- register_class_with_precision m, %r(time)i, Type::Time
616
- register_class_with_precision m, %r(datetime)i, Type::DateTime
617
- register_class_with_limit m, %r(float)i, Type::Float
618
- register_class_with_limit m, %r(int)i, Type::Integer
619
-
620
- m.alias_type %r(blob)i, "binary"
621
- m.alias_type %r(clob)i, "text"
622
- m.alias_type %r(timestamp)i, "datetime"
623
- m.alias_type %r(numeric)i, "decimal"
624
- m.alias_type %r(number)i, "decimal"
625
- m.alias_type %r(double)i, "float"
626
-
627
- m.register_type %r(^json)i, Type::Json.new
628
-
629
- m.register_type(%r(decimal)i) do |sql_type|
630
- scale = extract_scale(sql_type)
631
- precision = extract_precision(sql_type)
632
-
633
- if scale == 0
634
- # FIXME: Remove this class as well
635
- Type::DecimalWithoutScale.new(precision: precision)
636
- else
637
- Type::Decimal.new(precision: precision, scale: scale)
641
+ Arel::Nodes::Ascending.new(node.else(values.length + 1))
642
+ end
643
+
644
+ class << self
645
+ private
646
+ def initialize_type_map(m)
647
+ register_class_with_limit m, %r(boolean)i, Type::Boolean
648
+ register_class_with_limit m, %r(char)i, Type::String
649
+ register_class_with_limit m, %r(binary)i, Type::Binary
650
+ register_class_with_limit m, %r(text)i, Type::Text
651
+ register_class_with_precision m, %r(date)i, Type::Date
652
+ register_class_with_precision m, %r(time)i, Type::Time
653
+ register_class_with_precision m, %r(datetime)i, Type::DateTime
654
+ register_class_with_limit m, %r(float)i, Type::Float
655
+ register_class_with_limit m, %r(int)i, Type::Integer
656
+
657
+ m.alias_type %r(blob)i, "binary"
658
+ m.alias_type %r(clob)i, "text"
659
+ m.alias_type %r(timestamp)i, "datetime"
660
+ m.alias_type %r(numeric)i, "decimal"
661
+ m.alias_type %r(number)i, "decimal"
662
+ m.alias_type %r(double)i, "float"
663
+
664
+ m.register_type %r(^json)i, Type::Json.new
665
+
666
+ m.register_type(%r(decimal)i) do |sql_type|
667
+ scale = extract_scale(sql_type)
668
+ precision = extract_precision(sql_type)
669
+
670
+ if scale == 0
671
+ # FIXME: Remove this class as well
672
+ Type::DecimalWithoutScale.new(precision: precision)
673
+ else
674
+ Type::Decimal.new(precision: precision, scale: scale)
675
+ end
638
676
  end
639
677
  end
640
- end
641
678
 
642
- def reload_type_map
643
- type_map.clear
644
- initialize_type_map
645
- end
679
+ def register_class_with_limit(mapping, key, klass)
680
+ mapping.register_type(key) do |*args|
681
+ limit = extract_limit(args.last)
682
+ klass.new(limit: limit)
683
+ end
684
+ end
646
685
 
647
- def register_class_with_limit(mapping, key, klass)
648
- mapping.register_type(key) do |*args|
649
- limit = extract_limit(args.last)
650
- klass.new(limit: limit)
686
+ def register_class_with_precision(mapping, key, klass)
687
+ mapping.register_type(key) do |*args|
688
+ precision = extract_precision(args.last)
689
+ klass.new(precision: precision)
690
+ end
651
691
  end
652
- end
653
692
 
654
- def register_class_with_precision(mapping, key, klass)
655
- mapping.register_type(key) do |*args|
656
- precision = extract_precision(args.last)
657
- klass.new(precision: precision)
693
+ def extract_scale(sql_type)
694
+ case sql_type
695
+ when /\((\d+)\)/ then 0
696
+ when /\((\d+)(,(\d+))\)/ then $3.to_i
697
+ end
658
698
  end
659
- end
660
699
 
661
- def extract_scale(sql_type)
662
- case sql_type
663
- when /\((\d+)\)/ then 0
664
- when /\((\d+)(,(\d+))\)/ then $3.to_i
700
+ def extract_precision(sql_type)
701
+ $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
665
702
  end
666
- end
667
703
 
668
- def extract_precision(sql_type)
669
- $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
670
- end
704
+ def extract_limit(sql_type)
705
+ $1.to_i if sql_type =~ /\((.*)\)/
706
+ end
707
+ end
708
+
709
+ TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
671
710
 
672
- def extract_limit(sql_type)
673
- $1.to_i if sql_type =~ /\((.*)\)/
711
+ private
712
+ def type_map
713
+ TYPE_MAP
674
714
  end
675
715
 
676
716
  def translate_exception_class(e, sql, binds)
@@ -683,7 +723,7 @@ module ActiveRecord
683
723
  exception
684
724
  end
685
725
 
686
- def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil) # :doc:
726
+ def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false, &block) # :doc:
687
727
  @instrumenter.instrument(
688
728
  "sql.active_record",
689
729
  sql: sql,
@@ -691,15 +731,21 @@ module ActiveRecord
691
731
  binds: binds,
692
732
  type_casted_binds: type_casted_binds,
693
733
  statement_name: statement_name,
734
+ async: async,
694
735
  connection: self) do
695
- @lock.synchronize do
696
- yield
697
- end
736
+ @lock.synchronize(&block)
698
737
  rescue => e
699
738
  raise translate_exception_class(e, sql, binds)
700
739
  end
701
740
  end
702
741
 
742
+ def transform_query(sql)
743
+ ActiveRecord.query_transformers.each do |transformer|
744
+ sql = transformer.call(sql)
745
+ end
746
+ sql
747
+ end
748
+
703
749
  def translate_exception(exception, message:, sql:, binds:)
704
750
  # override in derived class
705
751
  case exception
@@ -54,7 +54,7 @@ module ActiveRecord
54
54
  super(connection, logger, config)
55
55
  end
56
56
 
57
- def get_database_version #:nodoc:
57
+ def get_database_version # :nodoc:
58
58
  full_version_string = get_full_version
59
59
  version_string = version_string(full_version_string)
60
60
  Version.new(version_string, full_version_string)
@@ -137,6 +137,11 @@ module ActiveRecord
137
137
  true
138
138
  end
139
139
 
140
+ def field_ordered_value(column, values) # :nodoc:
141
+ field = Arel::Nodes::NamedFunction.new("FIELD", [column, values.reverse])
142
+ Arel::Nodes::Descending.new(field)
143
+ end
144
+
140
145
  def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
141
146
  query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
142
147
  end
@@ -174,7 +179,7 @@ module ActiveRecord
174
179
 
175
180
  # REFERENTIAL INTEGRITY ====================================
176
181
 
177
- def disable_referential_integrity #:nodoc:
182
+ def disable_referential_integrity # :nodoc:
178
183
  old = query_value("SELECT @@FOREIGN_KEY_CHECKS")
179
184
 
180
185
  begin
@@ -185,54 +190,40 @@ module ActiveRecord
185
190
  end
186
191
  end
187
192
 
188
- # CONNECTION MANAGEMENT ====================================
189
-
190
- def clear_cache! # :nodoc:
191
- reload_type_map
192
- super
193
- end
194
-
195
193
  #--
196
194
  # DATABASE STATEMENTS ======================================
197
195
  #++
198
196
 
199
197
  # Executes the SQL statement in the context of this connection.
200
- def execute(sql, name = nil)
201
- materialize_transactions
202
- mark_transaction_written_if_write(sql)
203
-
204
- log(sql, name) do
205
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
206
- @connection.query(sql)
207
- end
208
- end
198
+ def execute(sql, name = nil, async: false)
199
+ raw_execute(sql, name, async)
209
200
  end
210
201
 
211
202
  # Mysql2Adapter doesn't have to free a result after using it, but we use this method
212
203
  # to write stuff in an abstract way without concerning ourselves about whether it
213
204
  # needs to be explicitly freed or not.
214
- def execute_and_free(sql, name = nil) # :nodoc:
215
- yield execute(sql, name)
205
+ def execute_and_free(sql, name = nil, async: false) # :nodoc:
206
+ yield execute(sql, name, async: async)
216
207
  end
217
208
 
218
- def begin_db_transaction
209
+ def begin_db_transaction # :nodoc:
219
210
  execute("BEGIN", "TRANSACTION")
220
211
  end
221
212
 
222
- def begin_isolated_db_transaction(isolation)
213
+ def begin_isolated_db_transaction(isolation) # :nodoc:
223
214
  execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
224
215
  begin_db_transaction
225
216
  end
226
217
 
227
- def commit_db_transaction #:nodoc:
218
+ def commit_db_transaction # :nodoc:
228
219
  execute("COMMIT", "TRANSACTION")
229
220
  end
230
221
 
231
- def exec_rollback_db_transaction #:nodoc:
222
+ def exec_rollback_db_transaction # :nodoc:
232
223
  execute("ROLLBACK", "TRANSACTION")
233
224
  end
234
225
 
235
- def empty_insert_statement_value(primary_key = nil)
226
+ def empty_insert_statement_value(primary_key = nil) # :nodoc:
236
227
  "VALUES ()"
237
228
  end
238
229
 
@@ -270,7 +261,7 @@ module ActiveRecord
270
261
  #
271
262
  # Example:
272
263
  # drop_database('sebastian_development')
273
- def drop_database(name) #:nodoc:
264
+ def drop_database(name) # :nodoc:
274
265
  execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
275
266
  end
276
267
 
@@ -346,12 +337,12 @@ module ActiveRecord
346
337
  end
347
338
  end
348
339
 
349
- def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
340
+ def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
350
341
  default = extract_new_default_value(default_or_changes)
351
342
  change_column table_name, column_name, nil, default: default
352
343
  end
353
344
 
354
- def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
345
+ def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
355
346
  unless null || default.nil?
356
347
  execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
357
348
  end
@@ -364,16 +355,16 @@ module ActiveRecord
364
355
  change_column table_name, column_name, nil, comment: comment
365
356
  end
366
357
 
367
- def change_column(table_name, column_name, type, **options) #:nodoc:
358
+ def change_column(table_name, column_name, type, **options) # :nodoc:
368
359
  execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
369
360
  end
370
361
 
371
- def rename_column(table_name, column_name, new_column_name) #:nodoc:
362
+ def rename_column(table_name, column_name, new_column_name) # :nodoc:
372
363
  execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
373
364
  rename_column_indexes(table_name, column_name, new_column_name)
374
365
  end
375
366
 
376
- def add_index(table_name, column_name, **options) #:nodoc:
367
+ def add_index(table_name, column_name, **options) # :nodoc:
377
368
  index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
378
369
 
379
370
  return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
@@ -427,7 +418,7 @@ module ActiveRecord
427
418
  if supports_check_constraints?
428
419
  scope = quoted_scope(table_name)
429
420
 
430
- chk_info = exec_query(<<~SQL, "SCHEMA")
421
+ sql = <<~SQL
431
422
  SELECT cc.constraint_name AS 'name',
432
423
  cc.check_clause AS 'expression'
433
424
  FROM information_schema.check_constraints cc
@@ -437,6 +428,9 @@ module ActiveRecord
437
428
  AND tc.table_name = #{scope[:name]}
438
429
  AND cc.constraint_schema = #{scope[:schema]}
439
430
  SQL
431
+ sql += " AND cc.table_name = #{scope[:name]}" if mariadb?
432
+
433
+ chk_info = exec_query(sql, "SCHEMA")
440
434
 
441
435
  chk_info.map do |row|
442
436
  options = {
@@ -548,8 +542,12 @@ module ActiveRecord
548
542
  sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
549
543
  elsif insert.update_duplicates?
550
544
  sql << " ON DUPLICATE KEY UPDATE "
551
- sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
552
- sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
545
+ if insert.raw_update_sql?
546
+ sql << insert.raw_update_sql
547
+ else
548
+ sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
549
+ sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
550
+ end
553
551
  end
554
552
 
555
553
  sql
@@ -561,55 +559,77 @@ module ActiveRecord
561
559
  end
562
560
  end
563
561
 
564
- private
565
- def initialize_type_map(m = type_map)
566
- super
562
+ class << self
563
+ private
564
+ def initialize_type_map(m)
565
+ super
567
566
 
568
- m.register_type(%r(char)i) do |sql_type|
569
- limit = extract_limit(sql_type)
570
- Type.lookup(:string, adapter: :mysql2, limit: limit)
567
+ m.register_type(%r(char)i) do |sql_type|
568
+ limit = extract_limit(sql_type)
569
+ Type.lookup(:string, adapter: :mysql2, limit: limit)
570
+ end
571
+
572
+ m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
573
+ m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
574
+ m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
575
+ m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
576
+ m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
577
+ m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
578
+ m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
579
+ m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
580
+ m.register_type %r(^float)i, Type::Float.new(limit: 24)
581
+ m.register_type %r(^double)i, Type::Float.new(limit: 53)
582
+
583
+ register_integer_type m, %r(^bigint)i, limit: 8
584
+ register_integer_type m, %r(^int)i, limit: 4
585
+ register_integer_type m, %r(^mediumint)i, limit: 3
586
+ register_integer_type m, %r(^smallint)i, limit: 2
587
+ register_integer_type m, %r(^tinyint)i, limit: 1
588
+
589
+ m.alias_type %r(year)i, "integer"
590
+ m.alias_type %r(bit)i, "binary"
591
+
592
+ m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
593
+ m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
571
594
  end
572
595
 
573
- m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
574
- m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
575
- m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
576
- m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
577
- m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
578
- m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
579
- m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
580
- m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
581
- m.register_type %r(^float)i, Type::Float.new(limit: 24)
582
- m.register_type %r(^double)i, Type::Float.new(limit: 53)
583
-
584
- register_integer_type m, %r(^bigint)i, limit: 8
585
- register_integer_type m, %r(^int)i, limit: 4
586
- register_integer_type m, %r(^mediumint)i, limit: 3
587
- register_integer_type m, %r(^smallint)i, limit: 2
588
- register_integer_type m, %r(^tinyint)i, limit: 1
589
-
590
- m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
591
- m.alias_type %r(year)i, "integer"
592
- m.alias_type %r(bit)i, "binary"
593
-
594
- m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
595
- m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
596
- end
596
+ def register_integer_type(mapping, key, **options)
597
+ mapping.register_type(key) do |sql_type|
598
+ if /\bunsigned\b/.match?(sql_type)
599
+ Type::UnsignedInteger.new(**options)
600
+ else
601
+ Type::Integer.new(**options)
602
+ end
603
+ end
604
+ end
597
605
 
598
- def register_integer_type(mapping, key, **options)
599
- mapping.register_type(key) do |sql_type|
600
- if /\bunsigned\b/.match?(sql_type)
601
- Type::UnsignedInteger.new(**options)
606
+ def extract_precision(sql_type)
607
+ if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
608
+ super || 0
602
609
  else
603
- Type::Integer.new(**options)
610
+ super
604
611
  end
605
612
  end
613
+ end
614
+
615
+ TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
616
+ TYPE_MAP_WITH_BOOLEAN = Type::TypeMap.new(TYPE_MAP).tap do |m|
617
+ m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
618
+ end
619
+
620
+ private
621
+ def type_map
622
+ emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
606
623
  end
607
624
 
608
- def extract_precision(sql_type)
609
- if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
610
- super || 0
611
- else
612
- super
625
+ def raw_execute(sql, name, async: false)
626
+ materialize_transactions
627
+ mark_transaction_written_if_write(sql)
628
+
629
+ log(sql, name, async: async) do
630
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
631
+ @connection.query(sql)
632
+ end
613
633
  end
614
634
  end
615
635
 
@@ -780,14 +800,13 @@ module ActiveRecord
780
800
  end
781
801
 
782
802
  # Gather up all of the SET variables...
783
- variable_assignments = variables.map do |k, v|
803
+ variable_assignments = variables.filter_map do |k, v|
784
804
  if defaults.include?(v)
785
805
  "@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
786
806
  elsif !v.nil?
787
807
  "@@SESSION.#{k} = #{quote(v)}"
788
808
  end
789
- # or else nil; compact to clear nils out
790
- end.compact.join(", ")
809
+ end.join(", ")
791
810
 
792
811
  # ...and send them all in one query
793
812
  execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
@@ -839,10 +858,6 @@ module ActiveRecord
839
858
  full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
840
859
  end
841
860
 
842
- # Alias MysqlString to work Mashal.load(File.read("legacy_record.dump")).
843
- # TODO: Remove the constant alias once Rails 6.1 has released.
844
- MysqlString = Type::String # :nodoc:
845
-
846
861
  ActiveRecord::Type.register(:immutable_string, adapter: :mysql2) do |_, **args|
847
862
  Type::ImmutableString.new(true: "1", false: "0", **args)
848
863
  end