activerecord 6.1.4.6 → 7.0.2.3

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 (240) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1188 -932
  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 +33 -17
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  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 +10 -3
  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 +34 -27
  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/join_dependency.rb +6 -2
  25. data/lib/active_record/associations/preloader/association.rb +187 -55
  26. data/lib/active_record/associations/preloader/batch.rb +48 -0
  27. data/lib/active_record/associations/preloader/branch.rb +147 -0
  28. data/lib/active_record/associations/preloader/through_association.rb +49 -13
  29. data/lib/active_record/associations/preloader.rb +39 -113
  30. data/lib/active_record/associations/singular_association.rb +8 -2
  31. data/lib/active_record/associations/through_association.rb +3 -3
  32. data/lib/active_record/associations.rb +119 -90
  33. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  34. data/lib/active_record/attribute_assignment.rb +1 -1
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  36. data/lib/active_record/attribute_methods/dirty.rb +49 -16
  37. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  38. data/lib/active_record/attribute_methods/query.rb +2 -2
  39. data/lib/active_record/attribute_methods/read.rb +7 -5
  40. data/lib/active_record/attribute_methods/serialization.rb +66 -12
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  42. data/lib/active_record/attribute_methods/write.rb +7 -10
  43. data/lib/active_record/attribute_methods.rb +13 -14
  44. data/lib/active_record/attributes.rb +24 -35
  45. data/lib/active_record/autosave_association.rb +8 -23
  46. data/lib/active_record/base.rb +19 -1
  47. data/lib/active_record/callbacks.rb +2 -2
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -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 +47 -561
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
  56. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  57. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +38 -13
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +78 -22
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +97 -81
  63. data/lib/active_record/connection_adapters/column.rb +4 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +38 -24
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +35 -21
  66. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +5 -1
  68. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  69. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  70. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
  71. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -12
  72. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  75. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  76. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  80. data/lib/active_record/connection_adapters/postgresql/quoting.rb +50 -50
  81. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  82. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  83. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
  84. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  85. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +35 -19
  86. data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -107
  87. data/lib/active_record/connection_adapters/schema_cache.rb +29 -4
  88. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +27 -19
  89. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
  90. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +16 -14
  91. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +89 -30
  92. data/lib/active_record/connection_adapters.rb +6 -5
  93. data/lib/active_record/connection_handling.rb +47 -53
  94. data/lib/active_record/core.rb +122 -132
  95. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
  96. data/lib/active_record/database_configurations/database_config.rb +12 -9
  97. data/lib/active_record/database_configurations/hash_config.rb +63 -5
  98. data/lib/active_record/database_configurations/url_config.rb +2 -2
  99. data/lib/active_record/database_configurations.rb +16 -32
  100. data/lib/active_record/delegated_type.rb +52 -11
  101. data/lib/active_record/destroy_association_async_job.rb +1 -1
  102. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  103. data/lib/active_record/dynamic_matchers.rb +1 -1
  104. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  105. data/lib/active_record/encryption/cipher.rb +53 -0
  106. data/lib/active_record/encryption/config.rb +44 -0
  107. data/lib/active_record/encryption/configurable.rb +61 -0
  108. data/lib/active_record/encryption/context.rb +35 -0
  109. data/lib/active_record/encryption/contexts.rb +72 -0
  110. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  111. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  112. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  113. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  114. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  115. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  116. data/lib/active_record/encryption/encryptor.rb +155 -0
  117. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  118. data/lib/active_record/encryption/errors.rb +15 -0
  119. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  120. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  121. data/lib/active_record/encryption/key.rb +28 -0
  122. data/lib/active_record/encryption/key_generator.rb +42 -0
  123. data/lib/active_record/encryption/key_provider.rb +46 -0
  124. data/lib/active_record/encryption/message.rb +33 -0
  125. data/lib/active_record/encryption/message_serializer.rb +90 -0
  126. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  127. data/lib/active_record/encryption/properties.rb +76 -0
  128. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  129. data/lib/active_record/encryption/scheme.rb +99 -0
  130. data/lib/active_record/encryption.rb +55 -0
  131. data/lib/active_record/enum.rb +49 -42
  132. data/lib/active_record/errors.rb +67 -4
  133. data/lib/active_record/explain_registry.rb +11 -6
  134. data/lib/active_record/fixture_set/file.rb +15 -1
  135. data/lib/active_record/fixture_set/table_row.rb +41 -6
  136. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  137. data/lib/active_record/fixtures.rb +17 -20
  138. data/lib/active_record/future_result.rb +139 -0
  139. data/lib/active_record/gem_version.rb +4 -4
  140. data/lib/active_record/inheritance.rb +55 -17
  141. data/lib/active_record/insert_all.rb +80 -14
  142. data/lib/active_record/integration.rb +4 -3
  143. data/lib/active_record/internal_metadata.rb +3 -5
  144. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  145. data/lib/active_record/locking/optimistic.rb +10 -9
  146. data/lib/active_record/locking/pessimistic.rb +9 -3
  147. data/lib/active_record/log_subscriber.rb +14 -3
  148. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  149. data/lib/active_record/middleware/database_selector.rb +8 -3
  150. data/lib/active_record/middleware/shard_selector.rb +60 -0
  151. data/lib/active_record/migration/command_recorder.rb +4 -4
  152. data/lib/active_record/migration/compatibility.rb +107 -3
  153. data/lib/active_record/migration/join_table.rb +1 -1
  154. data/lib/active_record/migration.rb +109 -79
  155. data/lib/active_record/model_schema.rb +45 -58
  156. data/lib/active_record/nested_attributes.rb +13 -12
  157. data/lib/active_record/no_touching.rb +3 -3
  158. data/lib/active_record/null_relation.rb +2 -6
  159. data/lib/active_record/persistence.rb +219 -52
  160. data/lib/active_record/query_cache.rb +2 -2
  161. data/lib/active_record/query_logs.rb +138 -0
  162. data/lib/active_record/querying.rb +15 -5
  163. data/lib/active_record/railtie.rb +127 -17
  164. data/lib/active_record/railties/controller_runtime.rb +1 -1
  165. data/lib/active_record/railties/databases.rake +66 -129
  166. data/lib/active_record/readonly_attributes.rb +11 -0
  167. data/lib/active_record/reflection.rb +67 -50
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  169. data/lib/active_record/relation/batches.rb +3 -3
  170. data/lib/active_record/relation/calculations.rb +43 -38
  171. data/lib/active_record/relation/delegation.rb +7 -7
  172. data/lib/active_record/relation/finder_methods.rb +31 -35
  173. data/lib/active_record/relation/merger.rb +20 -13
  174. data/lib/active_record/relation/predicate_builder.rb +1 -6
  175. data/lib/active_record/relation/query_attribute.rb +5 -11
  176. data/lib/active_record/relation/query_methods.rb +249 -61
  177. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  178. data/lib/active_record/relation/spawn_methods.rb +2 -2
  179. data/lib/active_record/relation/where_clause.rb +10 -19
  180. data/lib/active_record/relation.rb +184 -84
  181. data/lib/active_record/result.rb +17 -7
  182. data/lib/active_record/runtime_registry.rb +9 -13
  183. data/lib/active_record/sanitization.rb +11 -7
  184. data/lib/active_record/schema.rb +38 -23
  185. data/lib/active_record/schema_dumper.rb +25 -19
  186. data/lib/active_record/schema_migration.rb +4 -4
  187. data/lib/active_record/scoping/default.rb +61 -12
  188. data/lib/active_record/scoping/named.rb +3 -11
  189. data/lib/active_record/scoping.rb +64 -34
  190. data/lib/active_record/serialization.rb +1 -1
  191. data/lib/active_record/signed_id.rb +1 -1
  192. data/lib/active_record/suppressor.rb +11 -15
  193. data/lib/active_record/tasks/database_tasks.rb +120 -58
  194. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  195. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -12
  196. data/lib/active_record/test_databases.rb +1 -1
  197. data/lib/active_record/test_fixtures.rb +4 -4
  198. data/lib/active_record/timestamp.rb +3 -4
  199. data/lib/active_record/transactions.rb +9 -14
  200. data/lib/active_record/translation.rb +2 -2
  201. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  202. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  203. data/lib/active_record/type/internal/timezone.rb +2 -2
  204. data/lib/active_record/type/serialized.rb +1 -1
  205. data/lib/active_record/type/type_map.rb +17 -20
  206. data/lib/active_record/type.rb +1 -2
  207. data/lib/active_record/validations/associated.rb +1 -1
  208. data/lib/active_record/validations/uniqueness.rb +1 -1
  209. data/lib/active_record.rb +204 -28
  210. data/lib/arel/attributes/attribute.rb +0 -8
  211. data/lib/arel/crud.rb +28 -22
  212. data/lib/arel/delete_manager.rb +18 -4
  213. data/lib/arel/filter_predications.rb +9 -0
  214. data/lib/arel/insert_manager.rb +2 -3
  215. data/lib/arel/nodes/casted.rb +1 -1
  216. data/lib/arel/nodes/delete_statement.rb +12 -13
  217. data/lib/arel/nodes/filter.rb +10 -0
  218. data/lib/arel/nodes/function.rb +1 -0
  219. data/lib/arel/nodes/insert_statement.rb +2 -2
  220. data/lib/arel/nodes/select_core.rb +2 -2
  221. data/lib/arel/nodes/select_statement.rb +2 -2
  222. data/lib/arel/nodes/update_statement.rb +8 -3
  223. data/lib/arel/nodes.rb +1 -0
  224. data/lib/arel/predications.rb +11 -3
  225. data/lib/arel/select_manager.rb +10 -4
  226. data/lib/arel/table.rb +0 -1
  227. data/lib/arel/tree_manager.rb +0 -12
  228. data/lib/arel/update_manager.rb +18 -4
  229. data/lib/arel/visitors/dot.rb +80 -90
  230. data/lib/arel/visitors/mysql.rb +8 -2
  231. data/lib/arel/visitors/postgresql.rb +0 -10
  232. data/lib/arel/visitors/to_sql.rb +58 -2
  233. data/lib/arel.rb +2 -1
  234. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  235. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  236. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  237. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  238. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  239. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  240. metadata +56 -11
@@ -36,7 +36,7 @@ module ActiveRecord
36
36
  include Savepoints
37
37
 
38
38
  SIMPLE_INT = /\A\d+\z/
39
- COMMENT_REGEX = %r{(?:\-\-.*\n)*|/\*(?:[^\*]|\*[^/])*\*/}m
39
+ COMMENT_REGEX = %r{(?:--.*\n)*|/\*(?:[^*]|\*[^/])*\*/}m
40
40
 
41
41
  attr_accessor :pool
42
42
  attr_reader :visitor, :owner, :logger, :lock
@@ -68,7 +68,7 @@ module ActiveRecord
68
68
  def self.build_read_query_regexp(*parts) # :nodoc:
69
69
  parts += DEFAULT_READ_QUERY
70
70
  parts = parts.map { |part| /#{part}/i }
71
- /\A(?:[\(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
71
+ /\A(?:[(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
72
72
  end
73
73
 
74
74
  def self.quoted_column_names # :nodoc:
@@ -88,7 +88,7 @@ module ActiveRecord
88
88
  @logger = logger
89
89
  @config = config
90
90
  @pool = ActiveRecord::ConnectionAdapters::NullPool.new
91
- @idle_since = Concurrent.monotonic_time
91
+ @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
92
92
  @visitor = arel_visitor
93
93
  @statements = build_statement_pool
94
94
  @lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
@@ -102,6 +102,25 @@ module ActiveRecord
102
102
  )
103
103
  end
104
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
+
105
124
  def replica?
106
125
  @config[:replica] || false
107
126
  end
@@ -121,10 +140,10 @@ module ActiveRecord
121
140
  # will return true based on +current_preventing_writes+.
122
141
  def preventing_writes?
123
142
  return true if replica?
124
- return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord::Base.legacy_connection_handling
125
- return false if connection_klass.nil?
143
+ return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord.legacy_connection_handling
144
+ return false if connection_class.nil?
126
145
 
127
- connection_klass.current_preventing_writes
146
+ connection_class.current_preventing_writes
128
147
  end
129
148
 
130
149
  def migrations_paths # :nodoc:
@@ -159,7 +178,7 @@ module ActiveRecord
159
178
  alias :prepared_statements :prepared_statements?
160
179
 
161
180
  def prepared_statements_disabled_cache # :nodoc:
162
- Thread.current[:ar_prepared_statements_disabled_cache] ||= Set.new
181
+ ActiveSupport::IsolatedExecutionState[:active_record_prepared_statements_disabled_cache] ||= Set.new
163
182
  end
164
183
 
165
184
  class Version
@@ -201,8 +220,20 @@ module ActiveRecord
201
220
  @owner = Thread.current
202
221
  end
203
222
 
204
- def connection_klass # :nodoc:
205
- @pool.connection_klass
223
+ def connection_class # :nodoc:
224
+ @pool.connection_class
225
+ end
226
+
227
+ # The role (ie :writing) for the current connection. In a
228
+ # non-multi role application, `:writing` is returned.
229
+ def role
230
+ @pool.role
231
+ end
232
+
233
+ # The shard (ie :default) for the current connection. In
234
+ # a non-sharded application, `:default` is returned.
235
+ def shard
236
+ @pool.shard
206
237
  end
207
238
 
208
239
  def schema_cache
@@ -223,7 +254,7 @@ module ActiveRecord
223
254
  "Current thread: #{Thread.current}."
224
255
  end
225
256
 
226
- @idle_since = Concurrent.monotonic_time
257
+ @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
227
258
  @owner = nil
228
259
  else
229
260
  raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
@@ -246,7 +277,7 @@ module ActiveRecord
246
277
  # Seconds since this connection was returned to the pool
247
278
  def seconds_idle # :nodoc:
248
279
  return 0 if in_use?
249
- Concurrent.monotonic_time - @idle_since
280
+ Process.clock_gettime(Process::CLOCK_MONOTONIC) - @idle_since
250
281
  end
251
282
 
252
283
  def unprepared_statement
@@ -344,6 +375,11 @@ module ActiveRecord
344
375
  false
345
376
  end
346
377
 
378
+ # Does this adapter support creating deferrable constraints?
379
+ def supports_deferrable_constraints?
380
+ false
381
+ end
382
+
347
383
  # Does this adapter support creating check constraints?
348
384
  def supports_check_constraints?
349
385
  false
@@ -418,6 +454,15 @@ module ActiveRecord
418
454
  false
419
455
  end
420
456
 
457
+ def supports_concurrent_connections?
458
+ true
459
+ end
460
+
461
+ def async_enabled? # :nodoc:
462
+ supports_concurrent_connections? &&
463
+ !ActiveRecord.async_query_executor.nil? && !pool.async_executor.nil?
464
+ end
465
+
421
466
  # This is meant to be implemented by the adapters that support extensions
422
467
  def disable_extension(name)
423
468
  end
@@ -426,6 +471,10 @@ module ActiveRecord
426
471
  def enable_extension(name)
427
472
  end
428
473
 
474
+ # This is meant to be implemented by the adapters that support custom enum types
475
+ def create_enum(*) # :nodoc:
476
+ end
477
+
429
478
  def advisory_locks_enabled? # :nodoc:
430
479
  supports_advisory_locks? && @advisory_locks_enabled
431
480
  end
@@ -461,6 +510,11 @@ module ActiveRecord
461
510
  yield
462
511
  end
463
512
 
513
+ # Override to check all foreign key constraints in a database.
514
+ def all_foreign_keys_valid?
515
+ true
516
+ end
517
+
464
518
  # CONNECTION MANAGEMENT ====================================
465
519
 
466
520
  # Checks whether the connection to the database is still active. This includes
@@ -599,78 +653,93 @@ module ActiveRecord
599
653
  def check_version # :nodoc:
600
654
  end
601
655
 
602
- private
603
- def type_map
604
- @type_map ||= Type::TypeMap.new.tap do |mapping|
605
- initialize_type_map(mapping)
606
- end
656
+ # Returns the version identifier of the schema currently available in
657
+ # the database. This is generally equal to the number of the highest-
658
+ # numbered migration that has been executed, or 0 if no schema
659
+ # information is present / the database is empty.
660
+ def schema_version
661
+ migration_context.current_version
662
+ end
663
+
664
+ def field_ordered_value(column, values) # :nodoc:
665
+ node = Arel::Nodes::Case.new(column)
666
+ values.each.with_index(1) do |value, order|
667
+ node.when(value).then(order)
607
668
  end
608
669
 
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)
670
+ Arel::Nodes::Ascending.new(node.else(values.length + 1))
671
+ end
672
+
673
+ class << self
674
+ private
675
+ def initialize_type_map(m)
676
+ register_class_with_limit m, %r(boolean)i, Type::Boolean
677
+ register_class_with_limit m, %r(char)i, Type::String
678
+ register_class_with_limit m, %r(binary)i, Type::Binary
679
+ register_class_with_limit m, %r(text)i, Type::Text
680
+ register_class_with_precision m, %r(date)i, Type::Date
681
+ register_class_with_precision m, %r(time)i, Type::Time
682
+ register_class_with_precision m, %r(datetime)i, Type::DateTime
683
+ register_class_with_limit m, %r(float)i, Type::Float
684
+ register_class_with_limit m, %r(int)i, Type::Integer
685
+
686
+ m.alias_type %r(blob)i, "binary"
687
+ m.alias_type %r(clob)i, "text"
688
+ m.alias_type %r(timestamp)i, "datetime"
689
+ m.alias_type %r(numeric)i, "decimal"
690
+ m.alias_type %r(number)i, "decimal"
691
+ m.alias_type %r(double)i, "float"
692
+
693
+ m.register_type %r(^json)i, Type::Json.new
694
+
695
+ m.register_type(%r(decimal)i) do |sql_type|
696
+ scale = extract_scale(sql_type)
697
+ precision = extract_precision(sql_type)
698
+
699
+ if scale == 0
700
+ # FIXME: Remove this class as well
701
+ Type::DecimalWithoutScale.new(precision: precision)
702
+ else
703
+ Type::Decimal.new(precision: precision, scale: scale)
704
+ end
638
705
  end
639
706
  end
640
- end
641
707
 
642
- def reload_type_map
643
- type_map.clear
644
- initialize_type_map
645
- end
708
+ def register_class_with_limit(mapping, key, klass)
709
+ mapping.register_type(key) do |*args|
710
+ limit = extract_limit(args.last)
711
+ klass.new(limit: limit)
712
+ end
713
+ end
646
714
 
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)
715
+ def register_class_with_precision(mapping, key, klass)
716
+ mapping.register_type(key) do |*args|
717
+ precision = extract_precision(args.last)
718
+ klass.new(precision: precision)
719
+ end
651
720
  end
652
- end
653
721
 
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)
722
+ def extract_scale(sql_type)
723
+ case sql_type
724
+ when /\((\d+)\)/ then 0
725
+ when /\((\d+)(,(\d+))\)/ then $3.to_i
726
+ end
658
727
  end
659
- end
660
728
 
661
- def extract_scale(sql_type)
662
- case sql_type
663
- when /\((\d+)\)/ then 0
664
- when /\((\d+)(,(\d+))\)/ then $3.to_i
729
+ def extract_precision(sql_type)
730
+ $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
665
731
  end
666
- end
667
732
 
668
- def extract_precision(sql_type)
669
- $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
670
- end
733
+ def extract_limit(sql_type)
734
+ $1.to_i if sql_type =~ /\((.*)\)/
735
+ end
736
+ end
737
+
738
+ TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
671
739
 
672
- def extract_limit(sql_type)
673
- $1.to_i if sql_type =~ /\((.*)\)/
740
+ private
741
+ def type_map
742
+ TYPE_MAP
674
743
  end
675
744
 
676
745
  def translate_exception_class(e, sql, binds)
@@ -683,7 +752,7 @@ module ActiveRecord
683
752
  exception
684
753
  end
685
754
 
686
- def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil) # :doc:
755
+ def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false, &block) # :doc:
687
756
  @instrumenter.instrument(
688
757
  "sql.active_record",
689
758
  sql: sql,
@@ -691,15 +760,21 @@ module ActiveRecord
691
760
  binds: binds,
692
761
  type_casted_binds: type_casted_binds,
693
762
  statement_name: statement_name,
763
+ async: async,
694
764
  connection: self) do
695
- @lock.synchronize do
696
- yield
697
- end
765
+ @lock.synchronize(&block)
698
766
  rescue => e
699
767
  raise translate_exception_class(e, sql, binds)
700
768
  end
701
769
  end
702
770
 
771
+ def transform_query(sql)
772
+ ActiveRecord.query_transformers.each do |transformer|
773
+ sql = transformer.call(sql)
774
+ end
775
+ sql
776
+ end
777
+
703
778
  def translate_exception(exception, message:, sql:, binds:)
704
779
  # override in derived class
705
780
  case exception
@@ -31,6 +31,7 @@ module ActiveRecord
31
31
  string: { name: "varchar", limit: 255 },
32
32
  text: { name: "text" },
33
33
  integer: { name: "int", limit: 4 },
34
+ bigint: { name: "bigint" },
34
35
  float: { name: "float", limit: 24 },
35
36
  decimal: { name: "decimal" },
36
37
  datetime: { name: "datetime" },
@@ -54,7 +55,7 @@ module ActiveRecord
54
55
  super(connection, logger, config)
55
56
  end
56
57
 
57
- def get_database_version #:nodoc:
58
+ def get_database_version # :nodoc:
58
59
  full_version_string = get_full_version
59
60
  version_string = version_string(full_version_string)
60
61
  Version.new(version_string, full_version_string)
@@ -137,6 +138,11 @@ module ActiveRecord
137
138
  true
138
139
  end
139
140
 
141
+ def field_ordered_value(column, values) # :nodoc:
142
+ field = Arel::Nodes::NamedFunction.new("FIELD", [column, values.reverse])
143
+ Arel::Nodes::Descending.new(field)
144
+ end
145
+
140
146
  def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
141
147
  query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
142
148
  end
@@ -174,7 +180,7 @@ module ActiveRecord
174
180
 
175
181
  # REFERENTIAL INTEGRITY ====================================
176
182
 
177
- def disable_referential_integrity #:nodoc:
183
+ def disable_referential_integrity # :nodoc:
178
184
  old = query_value("SELECT @@FOREIGN_KEY_CHECKS")
179
185
 
180
186
  begin
@@ -185,54 +191,40 @@ module ActiveRecord
185
191
  end
186
192
  end
187
193
 
188
- # CONNECTION MANAGEMENT ====================================
189
-
190
- def clear_cache! # :nodoc:
191
- reload_type_map
192
- super
193
- end
194
-
195
194
  #--
196
195
  # DATABASE STATEMENTS ======================================
197
196
  #++
198
197
 
199
198
  # 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
199
+ def execute(sql, name = nil, async: false)
200
+ raw_execute(sql, name, async: async)
209
201
  end
210
202
 
211
203
  # Mysql2Adapter doesn't have to free a result after using it, but we use this method
212
204
  # to write stuff in an abstract way without concerning ourselves about whether it
213
205
  # needs to be explicitly freed or not.
214
- def execute_and_free(sql, name = nil) # :nodoc:
215
- yield execute(sql, name)
206
+ def execute_and_free(sql, name = nil, async: false) # :nodoc:
207
+ yield execute(sql, name, async: async)
216
208
  end
217
209
 
218
- def begin_db_transaction
210
+ def begin_db_transaction # :nodoc:
219
211
  execute("BEGIN", "TRANSACTION")
220
212
  end
221
213
 
222
- def begin_isolated_db_transaction(isolation)
214
+ def begin_isolated_db_transaction(isolation) # :nodoc:
223
215
  execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
224
216
  begin_db_transaction
225
217
  end
226
218
 
227
- def commit_db_transaction #:nodoc:
219
+ def commit_db_transaction # :nodoc:
228
220
  execute("COMMIT", "TRANSACTION")
229
221
  end
230
222
 
231
- def exec_rollback_db_transaction #:nodoc:
223
+ def exec_rollback_db_transaction # :nodoc:
232
224
  execute("ROLLBACK", "TRANSACTION")
233
225
  end
234
226
 
235
- def empty_insert_statement_value(primary_key = nil)
227
+ def empty_insert_statement_value(primary_key = nil) # :nodoc:
236
228
  "VALUES ()"
237
229
  end
238
230
 
@@ -270,7 +262,7 @@ module ActiveRecord
270
262
  #
271
263
  # Example:
272
264
  # drop_database('sebastian_development')
273
- def drop_database(name) #:nodoc:
265
+ def drop_database(name) # :nodoc:
274
266
  execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
275
267
  end
276
268
 
@@ -346,12 +338,12 @@ module ActiveRecord
346
338
  end
347
339
  end
348
340
 
349
- def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
341
+ def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
350
342
  default = extract_new_default_value(default_or_changes)
351
343
  change_column table_name, column_name, nil, default: default
352
344
  end
353
345
 
354
- def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
346
+ def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
355
347
  unless null || default.nil?
356
348
  execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
357
349
  end
@@ -364,16 +356,16 @@ module ActiveRecord
364
356
  change_column table_name, column_name, nil, comment: comment
365
357
  end
366
358
 
367
- def change_column(table_name, column_name, type, **options) #:nodoc:
359
+ def change_column(table_name, column_name, type, **options) # :nodoc:
368
360
  execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
369
361
  end
370
362
 
371
- def rename_column(table_name, column_name, new_column_name) #:nodoc:
363
+ def rename_column(table_name, column_name, new_column_name) # :nodoc:
372
364
  execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
373
365
  rename_column_indexes(table_name, column_name, new_column_name)
374
366
  end
375
367
 
376
- def add_index(table_name, column_name, **options) #:nodoc:
368
+ def add_index(table_name, column_name, **options) # :nodoc:
377
369
  index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
378
370
 
379
371
  return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
@@ -427,7 +419,7 @@ module ActiveRecord
427
419
  if supports_check_constraints?
428
420
  scope = quoted_scope(table_name)
429
421
 
430
- chk_info = exec_query(<<~SQL, "SCHEMA")
422
+ sql = <<~SQL
431
423
  SELECT cc.constraint_name AS 'name',
432
424
  cc.check_clause AS 'expression'
433
425
  FROM information_schema.check_constraints cc
@@ -437,6 +429,9 @@ module ActiveRecord
437
429
  AND tc.table_name = #{scope[:name]}
438
430
  AND cc.constraint_schema = #{scope[:schema]}
439
431
  SQL
432
+ sql += " AND cc.table_name = #{scope[:name]}" if mariadb?
433
+
434
+ chk_info = exec_query(sql, "SCHEMA")
440
435
 
441
436
  chk_info.map do |row|
442
437
  options = {
@@ -548,8 +543,12 @@ module ActiveRecord
548
543
  sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
549
544
  elsif insert.update_duplicates?
550
545
  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(",")
546
+ if insert.raw_update_sql?
547
+ sql << insert.raw_update_sql
548
+ else
549
+ sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
550
+ sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
551
+ end
553
552
  end
554
553
 
555
554
  sql
@@ -561,55 +560,77 @@ module ActiveRecord
561
560
  end
562
561
  end
563
562
 
564
- private
565
- def initialize_type_map(m = type_map)
566
- super
563
+ class << self
564
+ private
565
+ def initialize_type_map(m)
566
+ super
567
567
 
568
- m.register_type(%r(char)i) do |sql_type|
569
- limit = extract_limit(sql_type)
570
- Type.lookup(:string, adapter: :mysql2, limit: limit)
568
+ m.register_type(%r(char)i) do |sql_type|
569
+ limit = extract_limit(sql_type)
570
+ Type.lookup(:string, adapter: :mysql2, limit: limit)
571
+ end
572
+
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.alias_type %r(year)i, "integer"
591
+ m.alias_type %r(bit)i, "binary"
592
+
593
+ m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
594
+ m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
571
595
  end
572
596
 
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
597
+ def register_integer_type(mapping, key, **options)
598
+ mapping.register_type(key) do |sql_type|
599
+ if /\bunsigned\b/.match?(sql_type)
600
+ Type::UnsignedInteger.new(**options)
601
+ else
602
+ Type::Integer.new(**options)
603
+ end
604
+ end
605
+ end
597
606
 
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)
607
+ def extract_precision(sql_type)
608
+ if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
609
+ super || 0
602
610
  else
603
- Type::Integer.new(**options)
611
+ super
604
612
  end
605
613
  end
614
+ end
615
+
616
+ TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
617
+ TYPE_MAP_WITH_BOOLEAN = Type::TypeMap.new(TYPE_MAP).tap do |m|
618
+ m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
619
+ end
620
+
621
+ private
622
+ def type_map
623
+ emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
606
624
  end
607
625
 
608
- def extract_precision(sql_type)
609
- if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
610
- super || 0
611
- else
612
- super
626
+ def raw_execute(sql, name, async: false)
627
+ materialize_transactions
628
+ mark_transaction_written_if_write(sql)
629
+
630
+ log(sql, name, async: async) do
631
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
632
+ @connection.query(sql)
633
+ end
613
634
  end
614
635
  end
615
636
 
@@ -780,14 +801,13 @@ module ActiveRecord
780
801
  end
781
802
 
782
803
  # Gather up all of the SET variables...
783
- variable_assignments = variables.map do |k, v|
804
+ variable_assignments = variables.filter_map do |k, v|
784
805
  if defaults.include?(v)
785
806
  "@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
786
807
  elsif !v.nil?
787
808
  "@@SESSION.#{k} = #{quote(v)}"
788
809
  end
789
- # or else nil; compact to clear nils out
790
- end.compact.join(", ")
810
+ end.join(", ")
791
811
 
792
812
  # ...and send them all in one query
793
813
  execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
@@ -839,10 +859,6 @@ module ActiveRecord
839
859
  full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
840
860
  end
841
861
 
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
862
  ActiveRecord::Type.register(:immutable_string, adapter: :mysql2) do |_, **args|
847
863
  Type::ImmutableString.new(true: "1", false: "0", **args)
848
864
  end