activerecord 6.1.6 → 7.0.4

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 (243) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1314 -975
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/aggregations.rb +1 -1
  5. data/lib/active_record/association_relation.rb +0 -10
  6. data/lib/active_record/associations/association.rb +33 -17
  7. data/lib/active_record/associations/association_scope.rb +1 -3
  8. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  10. data/lib/active_record/associations/builder/association.rb +8 -2
  11. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  12. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  13. data/lib/active_record/associations/builder/has_many.rb +3 -2
  14. data/lib/active_record/associations/builder/has_one.rb +2 -1
  15. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  16. data/lib/active_record/associations/collection_association.rb +19 -21
  17. data/lib/active_record/associations/collection_proxy.rb +10 -5
  18. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  19. data/lib/active_record/associations/has_many_association.rb +8 -5
  20. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  21. data/lib/active_record/associations/has_one_association.rb +10 -7
  22. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  23. data/lib/active_record/associations/join_dependency.rb +23 -15
  24. data/lib/active_record/associations/preloader/association.rb +186 -52
  25. data/lib/active_record/associations/preloader/batch.rb +48 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +49 -13
  28. data/lib/active_record/associations/preloader.rb +39 -113
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +3 -3
  31. data/lib/active_record/associations.rb +124 -95
  32. data/lib/active_record/asynchronous_queries_tracker.rb +60 -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 +49 -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 +57 -19
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +14 -15
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +8 -23
  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 +10 -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 +80 -24
  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 +105 -81
  63. data/lib/active_record/connection_adapters/column.rb +4 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -24
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +37 -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 +20 -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 +19 -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 +51 -51
  81. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -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 +37 -19
  86. data/lib/active_record/connection_adapters/postgresql_adapter.rb +208 -107
  87. data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
  88. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
  89. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
  90. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +17 -15
  91. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +96 -32
  92. data/lib/active_record/connection_adapters.rb +6 -5
  93. data/lib/active_record/connection_handling.rb +49 -55
  94. data/lib/active_record/core.rb +124 -134
  95. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -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 +15 -32
  100. data/lib/active_record/delegated_type.rb +53 -12
  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 +67 -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 +206 -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 +50 -43
  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 +20 -23
  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 +1 -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 +10 -4
  147. data/lib/active_record/log_subscriber.rb +23 -7
  148. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  149. data/lib/active_record/middleware/database_selector.rb +18 -6
  150. data/lib/active_record/middleware/shard_selector.rb +60 -0
  151. data/lib/active_record/migration/command_recorder.rb +7 -7
  152. data/lib/active_record/migration/compatibility.rb +84 -2
  153. data/lib/active_record/migration/join_table.rb +1 -1
  154. data/lib/active_record/migration.rb +114 -83
  155. data/lib/active_record/model_schema.rb +58 -59
  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 +228 -60
  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 +16 -6
  163. data/lib/active_record/railtie.rb +136 -22
  164. data/lib/active_record/railties/controller_runtime.rb +1 -1
  165. data/lib/active_record/railties/databases.rake +78 -136
  166. data/lib/active_record/readonly_attributes.rb +11 -0
  167. data/lib/active_record/reflection.rb +73 -50
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  169. data/lib/active_record/relation/batches.rb +6 -6
  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 +276 -67
  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 +189 -88
  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 +17 -12
  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 +60 -13
  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 +6 -1
  191. data/lib/active_record/signed_id.rb +3 -3
  192. data/lib/active_record/store.rb +7 -2
  193. data/lib/active_record/suppressor.rb +11 -15
  194. data/lib/active_record/tasks/database_tasks.rb +127 -60
  195. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  196. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
  197. data/lib/active_record/test_databases.rb +1 -1
  198. data/lib/active_record/test_fixtures.rb +16 -9
  199. data/lib/active_record/timestamp.rb +3 -4
  200. data/lib/active_record/transactions.rb +9 -14
  201. data/lib/active_record/translation.rb +3 -3
  202. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  203. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  204. data/lib/active_record/type/internal/timezone.rb +2 -2
  205. data/lib/active_record/type/serialized.rb +1 -1
  206. data/lib/active_record/type/type_map.rb +17 -20
  207. data/lib/active_record/type.rb +1 -2
  208. data/lib/active_record/validations/associated.rb +4 -4
  209. data/lib/active_record/validations/presence.rb +2 -2
  210. data/lib/active_record/validations/uniqueness.rb +4 -4
  211. data/lib/active_record/version.rb +1 -1
  212. data/lib/active_record.rb +217 -27
  213. data/lib/arel/attributes/attribute.rb +0 -8
  214. data/lib/arel/crud.rb +28 -22
  215. data/lib/arel/delete_manager.rb +18 -4
  216. data/lib/arel/filter_predications.rb +9 -0
  217. data/lib/arel/insert_manager.rb +2 -3
  218. data/lib/arel/nodes/casted.rb +1 -1
  219. data/lib/arel/nodes/delete_statement.rb +12 -13
  220. data/lib/arel/nodes/filter.rb +10 -0
  221. data/lib/arel/nodes/function.rb +1 -0
  222. data/lib/arel/nodes/insert_statement.rb +2 -2
  223. data/lib/arel/nodes/select_core.rb +2 -2
  224. data/lib/arel/nodes/select_statement.rb +2 -2
  225. data/lib/arel/nodes/update_statement.rb +8 -3
  226. data/lib/arel/nodes.rb +1 -0
  227. data/lib/arel/predications.rb +11 -3
  228. data/lib/arel/select_manager.rb +10 -4
  229. data/lib/arel/table.rb +0 -1
  230. data/lib/arel/tree_manager.rb +0 -12
  231. data/lib/arel/update_manager.rb +18 -4
  232. data/lib/arel/visitors/dot.rb +80 -90
  233. data/lib/arel/visitors/mysql.rb +8 -2
  234. data/lib/arel/visitors/postgresql.rb +0 -10
  235. data/lib/arel/visitors/to_sql.rb +58 -2
  236. data/lib/arel.rb +2 -1
  237. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  238. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  239. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  240. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  241. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  242. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  243. metadata +55 -11
@@ -59,17 +59,13 @@ module ActiveRecord
59
59
  end
60
60
 
61
61
  # Returns an ActiveRecord::Result instance.
62
- def select_all(arel, name = nil, binds = [], preparable: nil)
62
+ def select_all(arel, name = nil, binds = [], preparable: nil, async: false)
63
63
  arel = arel_from_relation(arel)
64
64
  sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
65
65
 
66
- if prepared_statements && preparable
67
- select_prepared(sql, name, binds)
68
- else
69
- select(sql, name, binds)
70
- end
66
+ select(sql, name, binds, prepare: prepared_statements && preparable, async: async && FutureResult::SelectAll)
71
67
  rescue ::RangeError
72
- ActiveRecord::Result.new([], [])
68
+ ActiveRecord::Result.empty
73
69
  end
74
70
 
75
71
  # Returns a record hash with the column names as keys and column values
@@ -310,20 +306,20 @@ module ActiveRecord
310
306
  #
311
307
  # The mysql2 and postgresql adapters support setting the transaction
312
308
  # isolation level.
313
- def transaction(requires_new: nil, isolation: nil, joinable: true)
309
+ def transaction(requires_new: nil, isolation: nil, joinable: true, &block)
314
310
  if !requires_new && current_transaction.joinable?
315
311
  if isolation
316
312
  raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
317
313
  end
318
314
  yield
319
315
  else
320
- transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable) { yield }
316
+ transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable, &block)
321
317
  end
322
318
  rescue ActiveRecord::Rollback
323
319
  # rollbacks are silently swallowed
324
320
  end
325
321
 
326
- attr_reader :transaction_manager #:nodoc:
322
+ attr_reader :transaction_manager # :nodoc:
327
323
 
328
324
  delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
329
325
  :commit_transaction, :rollback_transaction, :materialize_transactions,
@@ -340,7 +336,7 @@ module ActiveRecord
340
336
  current_transaction.open?
341
337
  end
342
338
 
343
- def reset_transaction #:nodoc:
339
+ def reset_transaction # :nodoc:
344
340
  @transaction_manager = ConnectionAdapters::TransactionManager.new(self)
345
341
  end
346
342
 
@@ -378,7 +374,7 @@ module ActiveRecord
378
374
  exec_rollback_db_transaction
379
375
  end
380
376
 
381
- def exec_rollback_db_transaction() end #:nodoc:
377
+ def exec_rollback_db_transaction() end # :nodoc:
382
378
 
383
379
  def rollback_to_savepoint(name = nil)
384
380
  exec_rollback_to_savepoint(name)
@@ -445,6 +441,19 @@ module ActiveRecord
445
441
  end
446
442
  end
447
443
 
444
+ # This is a safe default, even if not high precision on all databases
445
+ HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP").freeze # :nodoc:
446
+ private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
447
+
448
+ # Returns an Arel SQL literal for the CURRENT_TIMESTAMP for usage with
449
+ # arbitrary precision date/time columns.
450
+ #
451
+ # Adapters supporting datetime with precision should override this to
452
+ # provide as much precision as is available.
453
+ def high_precision_current_timestamp
454
+ HIGH_PRECISION_CURRENT_TIMESTAMP
455
+ end
456
+
448
457
  private
449
458
  def execute_batch(statements, name = nil)
450
459
  statements.each do |statement|
@@ -460,7 +469,7 @@ module ActiveRecord
460
469
  end
461
470
 
462
471
  def build_fixture_sql(fixtures, table_name)
463
- columns = schema_cache.columns_hash(table_name)
472
+ columns = schema_cache.columns_hash(table_name).reject { |_, column| supports_virtual_columns? && column.virtual? }
464
473
 
465
474
  values_list = fixtures.map do |fixture|
466
475
  fixture = fixture.stringify_keys
@@ -481,8 +490,7 @@ module ActiveRecord
481
490
  end
482
491
 
483
492
  table = Arel::Table.new(table_name)
484
- manager = Arel::InsertManager.new
485
- manager.into(table)
493
+ manager = Arel::InsertManager.new(table)
486
494
 
487
495
  if values_list.size == 1
488
496
  values = values_list.shift
@@ -503,10 +511,10 @@ module ActiveRecord
503
511
  end
504
512
 
505
513
  def build_fixture_statements(fixture_set)
506
- fixture_set.map do |table_name, fixtures|
514
+ fixture_set.filter_map do |table_name, fixtures|
507
515
  next if fixtures.empty?
508
516
  build_fixture_sql(fixtures, table_name)
509
- end.compact
517
+ end
510
518
  end
511
519
 
512
520
  def build_truncate_statement(table_name)
@@ -528,12 +536,28 @@ module ActiveRecord
528
536
  end
529
537
 
530
538
  # Returns an ActiveRecord::Result instance.
531
- def select(sql, name = nil, binds = [])
532
- exec_query(sql, name, binds, prepare: false)
533
- end
539
+ def select(sql, name = nil, binds = [], prepare: false, async: false)
540
+ if async && async_enabled?
541
+ if current_transaction.joinable?
542
+ raise AsynchronousQueryInsideTransactionError, "Asynchronous queries are not allowed inside transactions"
543
+ end
544
+
545
+ future_result = async.new(
546
+ pool,
547
+ sql,
548
+ name,
549
+ binds,
550
+ prepare: prepare,
551
+ )
552
+ if supports_concurrent_connections? && current_transaction.closed?
553
+ future_result.schedule!(ActiveRecord::Base.asynchronous_queries_session)
554
+ else
555
+ future_result.execute!(self)
556
+ end
557
+ return future_result
558
+ end
534
559
 
535
- def select_prepared(sql, name = nil, binds = [])
536
- exec_query(sql, name, binds, prepare: true)
560
+ exec_query(sql, name, binds, prepare: prepare)
537
561
  end
538
562
 
539
563
  def sql_for_insert(sql, pk, binds)
@@ -6,7 +6,7 @@ module ActiveRecord
6
6
  module ConnectionAdapters # :nodoc:
7
7
  module QueryCache
8
8
  class << self
9
- def included(base) #:nodoc:
9
+ def included(base) # :nodoc:
10
10
  dirties_query_cache base, :create, :insert, :update, :delete, :truncate, :truncate_tables,
11
11
  :rollback_to_savepoint, :rollback_db_transaction, :exec_insert_all
12
12
 
@@ -93,18 +93,37 @@ module ActiveRecord
93
93
  end
94
94
  end
95
95
 
96
- def select_all(arel, name = nil, binds = [], preparable: nil)
97
- if @query_cache_enabled && !locked?(arel)
98
- arel = arel_from_relation(arel)
96
+ def select_all(arel, name = nil, binds = [], preparable: nil, async: false)
97
+ arel = arel_from_relation(arel)
98
+
99
+ # If arel is locked this is a SELECT ... FOR UPDATE or somesuch.
100
+ # Such queries should not be cached.
101
+ if @query_cache_enabled && !(arel.respond_to?(:locked) && arel.locked)
99
102
  sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
100
103
 
101
- cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) }
104
+ if async
105
+ lookup_sql_cache(sql, name, binds) || super(sql, name, binds, preparable: preparable, async: async)
106
+ else
107
+ cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable, async: async) }
108
+ end
102
109
  else
103
110
  super
104
111
  end
105
112
  end
106
113
 
107
114
  private
115
+ def lookup_sql_cache(sql, name, binds)
116
+ @lock.synchronize do
117
+ if @query_cache[sql].key?(binds)
118
+ ActiveSupport::Notifications.instrument(
119
+ "sql.active_record",
120
+ cache_notification_info(sql, name, binds)
121
+ )
122
+ @query_cache[sql][binds]
123
+ end
124
+ end
125
+ end
126
+
108
127
  def cache_sql(sql, name, binds)
109
128
  @lock.synchronize do
110
129
  result =
@@ -134,13 +153,6 @@ module ActiveRecord
134
153
  }
135
154
  end
136
155
 
137
- # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
138
- # queries should not be cached.
139
- def locked?(arel)
140
- arel = arel.arel if arel.is_a?(Relation)
141
- arel.respond_to?(:locked) && arel.locked
142
- end
143
-
144
156
  def configure_query_cache!
145
157
  enable_query_cache! if pool.query_cache_enabled
146
158
  end
@@ -9,38 +9,46 @@ module ActiveRecord
9
9
  # Quotes the column value to help prevent
10
10
  # {SQL injection attacks}[https://en.wikipedia.org/wiki/SQL_injection].
11
11
  def quote(value)
12
- if value.is_a?(Base)
13
- ActiveSupport::Deprecation.warn(<<~MSG)
14
- Passing an Active Record object to `quote` directly is deprecated
15
- and will be no longer quoted as id value in Rails 7.0.
16
- MSG
17
- value = value.id_for_database
12
+ case value
13
+ when String, Symbol, ActiveSupport::Multibyte::Chars
14
+ "'#{quote_string(value.to_s)}'"
15
+ when true then quoted_true
16
+ when false then quoted_false
17
+ when nil then "NULL"
18
+ # BigDecimals need to be put in a non-normalized form and quoted.
19
+ when BigDecimal then value.to_s("F")
20
+ when Numeric, ActiveSupport::Duration then value.to_s
21
+ when Type::Binary::Data then quoted_binary(value)
22
+ when Type::Time::Value then "'#{quoted_time(value)}'"
23
+ when Date, Time then "'#{quoted_date(value)}'"
24
+ when Class then "'#{value}'"
25
+ else raise TypeError, "can't quote #{value.class.name}"
18
26
  end
19
-
20
- _quote(value)
21
27
  end
22
28
 
23
29
  # Cast a +value+ to a type that the database understands. For example,
24
30
  # SQLite does not understand dates, so this method will convert a Date
25
31
  # to a String.
26
- def type_cast(value, column = nil)
27
- if value.is_a?(Base)
28
- ActiveSupport::Deprecation.warn(<<~MSG)
29
- Passing an Active Record object to `type_cast` directly is deprecated
30
- and will be no longer type casted as id value in Rails 7.0.
31
- MSG
32
- value = value.id_for_database
33
- end
34
-
35
- if column
36
- ActiveSupport::Deprecation.warn(<<~MSG)
37
- Passing a column to `type_cast` is deprecated and will be removed in Rails 7.0.
38
- MSG
39
- type = lookup_cast_type_from_column(column)
40
- value = type.serialize(value)
32
+ def type_cast(value)
33
+ case value
34
+ when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
35
+ value.to_s
36
+ when true then unquoted_true
37
+ when false then unquoted_false
38
+ # BigDecimals need to be put in a non-normalized form and quoted.
39
+ when BigDecimal then value.to_s("F")
40
+ when nil, Numeric, String then value
41
+ when Type::Time::Value then quoted_time(value)
42
+ when Date, Time then quoted_date(value)
43
+ else raise TypeError, "can't cast #{value.class.name}"
41
44
  end
45
+ end
42
46
 
43
- _type_cast(value)
47
+ # Quote a value to be used as a bound parameter of unknown type. For example,
48
+ # MySQL might perform dangerous castings when comparing a string to a number,
49
+ # so this method will cast numbers to string.
50
+ def quote_bound_value(value)
51
+ quote(value)
44
52
  end
45
53
 
46
54
  # If you are having to call this function, you are likely doing something
@@ -59,7 +67,7 @@ module ActiveRecord
59
67
  # Quotes a string, escaping any ' (single quote) and \ (backslash)
60
68
  # characters.
61
69
  def quote_string(s)
62
- s.gsub('\\', '\&\&').gsub("'", "''") # ' (for ruby-mode)
70
+ s.gsub("\\", '\&\&').gsub("'", "''") # ' (for ruby-mode)
63
71
  end
64
72
 
65
73
  # Quotes the column name. Defaults to no quoting.
@@ -113,14 +121,14 @@ module ActiveRecord
113
121
  # if the value is a Time responding to usec.
114
122
  def quoted_date(value)
115
123
  if value.acts_like?(:time)
116
- if ActiveRecord::Base.default_timezone == :utc
117
- value = value.getutc if value.respond_to?(:getutc) && !value.utc?
124
+ if ActiveRecord.default_timezone == :utc
125
+ value = value.getutc if !value.utc?
118
126
  else
119
- value = value.getlocal if value.respond_to?(:getlocal)
127
+ value = value.getlocal
120
128
  end
121
129
  end
122
130
 
123
- result = value.to_s(:db)
131
+ result = value.to_fs(:db)
124
132
  if value.respond_to?(:usec) && value.usec > 0
125
133
  result << "." << sprintf("%06d", value.usec)
126
134
  else
@@ -196,16 +204,11 @@ module ActiveRecord
196
204
 
197
205
  private
198
206
  def type_casted_binds(binds)
199
- case binds.first
200
- when Array
201
- binds.map { |column, value| type_cast(value, column) }
202
- else
203
- binds.map do |value|
204
- if ActiveModel::Attribute === value
205
- type_cast(value.value_for_database)
206
- else
207
- type_cast(value)
208
- end
207
+ binds.map do |value|
208
+ if ActiveModel::Attribute === value
209
+ type_cast(value.value_for_database)
210
+ else
211
+ type_cast(value)
209
212
  end
210
213
  end
211
214
  end
@@ -213,39 +216,6 @@ module ActiveRecord
213
216
  def lookup_cast_type(sql_type)
214
217
  type_map.lookup(sql_type)
215
218
  end
216
-
217
- def _quote(value)
218
- case value
219
- when String, Symbol, ActiveSupport::Multibyte::Chars
220
- "'#{quote_string(value.to_s)}'"
221
- when true then quoted_true
222
- when false then quoted_false
223
- when nil then "NULL"
224
- # BigDecimals need to be put in a non-normalized form and quoted.
225
- when BigDecimal then value.to_s("F")
226
- when Numeric, ActiveSupport::Duration then value.to_s
227
- when Type::Binary::Data then quoted_binary(value)
228
- when Type::Time::Value then "'#{quoted_time(value)}'"
229
- when Date, Time then "'#{quoted_date(value)}'"
230
- when Class then "'#{value}'"
231
- else raise TypeError, "can't quote #{value.class.name}"
232
- end
233
- end
234
-
235
- def _type_cast(value)
236
- case value
237
- when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
238
- value.to_s
239
- when true then unquoted_true
240
- when false then unquoted_false
241
- # BigDecimals need to be put in a non-normalized form and quoted.
242
- when BigDecimal then value.to_s("F")
243
- when nil, Numeric, String then value
244
- when Type::Time::Value then quoted_time(value)
245
- when Date, Time then quoted_date(value)
246
- else raise TypeError, "can't cast #{value.class.name}"
247
- end
248
- end
249
219
  end
250
220
  end
251
221
  end
@@ -14,8 +14,8 @@ module ActiveRecord
14
14
  end
15
15
 
16
16
  delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
17
- :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options,
18
- :quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?, :check_constraint_options,
17
+ :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?,
18
+ :quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?,
19
19
  to: :@conn, private: true
20
20
 
21
21
  private
@@ -52,11 +52,11 @@ module ActiveRecord
52
52
  end
53
53
 
54
54
  if supports_foreign_keys?
55
- statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
55
+ statements.concat(o.foreign_keys.map { |fk| accept fk })
56
56
  end
57
57
 
58
58
  if supports_check_constraints?
59
- statements.concat(o.check_constraints.map { |expression, options| check_constraint_in_create(o.name, expression, options) })
59
+ statements.concat(o.check_constraints.map { |chk| accept chk })
60
60
  end
61
61
 
62
62
  create_sql << "(#{statements.join(', ')})" if statements.present?
@@ -159,19 +159,6 @@ module ActiveRecord
159
159
  " TEMPORARY" if o.temporary
160
160
  end
161
161
 
162
- def foreign_key_in_create(from_table, to_table, options)
163
- prefix = ActiveRecord::Base.table_name_prefix
164
- suffix = ActiveRecord::Base.table_name_suffix
165
- to_table = "#{prefix}#{to_table}#{suffix}"
166
- options = foreign_key_options(from_table, to_table, options)
167
- accept ForeignKeyDefinition.new(from_table, to_table, options)
168
- end
169
-
170
- def check_constraint_in_create(table_name, expression, options)
171
- options = check_constraint_options(table_name, expression, options)
172
- accept CheckConstraintDefinition.new(table_name, expression, options)
173
- end
174
-
175
162
  def action_sql(action, dependency)
176
163
  case dependency
177
164
  when :nullify then "ON #{action} SET NULL"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- module ConnectionAdapters #:nodoc:
4
+ module ConnectionAdapters # :nodoc:
5
5
  # Abstract representation of an index definition on a table. Instances of
6
6
  # this type are typically created and returned by methods in database
7
7
  # adapters. e.g. ActiveRecord::ConnectionAdapters::MySQL::SchemaStatements#indexes
@@ -79,13 +79,13 @@ module ActiveRecord
79
79
 
80
80
  AddColumnDefinition = Struct.new(:column) # :nodoc:
81
81
 
82
- ChangeColumnDefinition = Struct.new(:column, :name) #:nodoc:
82
+ ChangeColumnDefinition = Struct.new(:column, :name) # :nodoc:
83
83
 
84
84
  CreateIndexDefinition = Struct.new(:index, :algorithm, :if_not_exists) # :nodoc:
85
85
 
86
86
  PrimaryKeyDefinition = Struct.new(:name) # :nodoc:
87
87
 
88
- ForeignKeyDefinition = Struct.new(:from_table, :to_table, :options) do #:nodoc:
88
+ ForeignKeyDefinition = Struct.new(:from_table, :to_table, :options) do # :nodoc:
89
89
  def name
90
90
  options[:name]
91
91
  end
@@ -106,6 +106,10 @@ module ActiveRecord
106
106
  options[:on_update]
107
107
  end
108
108
 
109
+ def deferrable
110
+ options[:deferrable]
111
+ end
112
+
109
113
  def custom_primary_key?
110
114
  options[:primary_key] != default_primary_key
111
115
  end
@@ -257,6 +261,7 @@ module ActiveRecord
257
261
  define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
258
262
  :float, :integer, :json, :string, :text, :time, :timestamp, :virtual
259
263
 
264
+ alias :blob :binary
260
265
  alias :numeric :decimal
261
266
  end
262
267
 
@@ -281,7 +286,7 @@ module ActiveRecord
281
286
  # Inside migration files, the +t+ object in {create_table}[rdoc-ref:SchemaStatements#create_table]
282
287
  # is actually of this type:
283
288
  #
284
- # class SomeMigration < ActiveRecord::Migration[6.0]
289
+ # class SomeMigration < ActiveRecord::Migration[7.0]
285
290
  # def up
286
291
  # create_table :foo do |t|
287
292
  # puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
@@ -414,6 +419,12 @@ module ActiveRecord
414
419
  end
415
420
  end
416
421
 
422
+ if @conn.supports_datetime_with_precision?
423
+ if type == :datetime && !options.key?(:precision)
424
+ options[:precision] = 6
425
+ end
426
+ end
427
+
417
428
  @columns_hash[name] = new_column_definition(name, type, **options)
418
429
 
419
430
  if index
@@ -438,12 +449,12 @@ module ActiveRecord
438
449
  indexes << [column_name, options]
439
450
  end
440
451
 
441
- def foreign_key(table_name, **options) # :nodoc:
442
- foreign_keys << [table_name, options]
452
+ def foreign_key(to_table, **options)
453
+ foreign_keys << new_foreign_key_definition(to_table, options)
443
454
  end
444
455
 
445
456
  def check_constraint(expression, **options)
446
- check_constraints << [expression, options]
457
+ check_constraints << new_check_constraint_definition(expression, options)
447
458
  end
448
459
 
449
460
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
@@ -485,6 +496,19 @@ module ActiveRecord
485
496
  create_column_definition(name, type, options)
486
497
  end
487
498
 
499
+ def new_foreign_key_definition(to_table, options) # :nodoc:
500
+ prefix = ActiveRecord::Base.table_name_prefix
501
+ suffix = ActiveRecord::Base.table_name_suffix
502
+ to_table = "#{prefix}#{to_table}#{suffix}"
503
+ options = @conn.foreign_key_options(name, to_table, options)
504
+ ForeignKeyDefinition.new(name, to_table, options)
505
+ end
506
+
507
+ def new_check_constraint_definition(expression, options) # :nodoc:
508
+ options = @conn.check_constraint_options(name, expression, options)
509
+ CheckConstraintDefinition.new(name, expression, options)
510
+ end
511
+
488
512
  private
489
513
  def create_column_definition(name, type, options)
490
514
  ColumnDefinition.new(name, type, options)
@@ -520,7 +544,7 @@ module ActiveRecord
520
544
  def name; @td.name; end
521
545
 
522
546
  def add_foreign_key(to_table, options)
523
- @foreign_key_adds << ForeignKeyDefinition.new(name, to_table, options)
547
+ @foreign_key_adds << @td.new_foreign_key_definition(to_table, options)
524
548
  end
525
549
 
526
550
  def drop_foreign_key(name)
@@ -528,7 +552,7 @@ module ActiveRecord
528
552
  end
529
553
 
530
554
  def add_check_constraint(expression, options)
531
- @check_constraint_adds << CheckConstraintDefinition.new(name, expression, options)
555
+ @check_constraint_adds << @td.new_check_constraint_definition(expression, options)
532
556
  end
533
557
 
534
558
  def drop_check_constraint(constraint_name)
@@ -572,6 +596,7 @@ module ActiveRecord
572
596
  # t.time
573
597
  # t.date
574
598
  # t.binary
599
+ # t.blob
575
600
  # t.boolean
576
601
  # t.foreign_key
577
602
  # t.json
@@ -789,8 +814,8 @@ module ActiveRecord
789
814
  # t.check_constraint("price > 0", name: "price_check")
790
815
  #
791
816
  # See {connection.add_check_constraint}[rdoc-ref:SchemaStatements#add_check_constraint]
792
- def check_constraint(*args)
793
- @base.add_check_constraint(name, *args)
817
+ def check_constraint(*args, **options)
818
+ @base.add_check_constraint(name, *args, **options)
794
819
  end
795
820
 
796
821
  # Removes the given check constraint from the table.
@@ -798,8 +823,8 @@ module ActiveRecord
798
823
  # t.remove_check_constraint(name: "price_check")
799
824
  #
800
825
  # See {connection.remove_check_constraint}[rdoc-ref:SchemaStatements#remove_check_constraint]
801
- def remove_check_constraint(*args)
802
- @base.remove_check_constraint(name, *args)
826
+ def remove_check_constraint(*args, **options)
827
+ @base.remove_check_constraint(name, *args, **options)
803
828
  end
804
829
  end
805
830
  end
@@ -3,6 +3,8 @@
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters # :nodoc:
5
5
  class SchemaDumper < SchemaDumper # :nodoc:
6
+ DEFAULT_DATETIME_PRECISION = 6 # :nodoc:
7
+
6
8
  def self.create(connection, options)
7
9
  new(connection, options)
8
10
  end
@@ -63,7 +65,18 @@ module ActiveRecord
63
65
  end
64
66
 
65
67
  def schema_precision(column)
66
- column.precision.inspect if column.precision
68
+ if column.type == :datetime
69
+ case column.precision
70
+ when nil
71
+ "nil"
72
+ when DEFAULT_DATETIME_PRECISION
73
+ nil
74
+ else
75
+ column.precision.inspect
76
+ end
77
+ elsif column.precision
78
+ column.precision.inspect
79
+ end
67
80
  end
68
81
 
69
82
  def schema_scale(column)