activerecord 6.1.7.8 → 7.0.8.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1582 -1018
  3. data/README.rdoc +3 -3
  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 +20 -22
  17. data/lib/active_record/associations/collection_proxy.rb +15 -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 +50 -14
  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 +138 -100
  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 +8 -6
  39. data/lib/active_record/attribute_methods/serialization.rb +57 -19
  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 +19 -22
  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 +14 -16
  47. data/lib/active_record/coders/yaml_column.rb +4 -8
  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 +52 -23
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +82 -25
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +144 -82
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +115 -85
  63. data/lib/active_record/connection_adapters/column.rb +4 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +37 -25
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -23
  66. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  68. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  70. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  71. data/lib/active_record/connection_adapters/postgresql/column.rb +19 -1
  72. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -17
  73. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  74. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  77. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  78. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  81. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  82. data/lib/active_record/connection_adapters/postgresql/quoting.rb +76 -73
  83. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
  84. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  85. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
  86. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  87. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +40 -21
  88. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  89. data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -106
  90. data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
  91. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
  92. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +33 -18
  93. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -0
  94. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +19 -17
  95. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +98 -36
  96. data/lib/active_record/connection_adapters.rb +6 -5
  97. data/lib/active_record/connection_handling.rb +49 -55
  98. data/lib/active_record/core.rb +123 -148
  99. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  100. data/lib/active_record/database_configurations/database_config.rb +12 -9
  101. data/lib/active_record/database_configurations/hash_config.rb +63 -5
  102. data/lib/active_record/database_configurations/url_config.rb +2 -2
  103. data/lib/active_record/database_configurations.rb +15 -32
  104. data/lib/active_record/delegated_type.rb +53 -12
  105. data/lib/active_record/destroy_association_async_job.rb +1 -1
  106. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  107. data/lib/active_record/dynamic_matchers.rb +1 -1
  108. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  109. data/lib/active_record/encryption/cipher.rb +53 -0
  110. data/lib/active_record/encryption/config.rb +44 -0
  111. data/lib/active_record/encryption/configurable.rb +67 -0
  112. data/lib/active_record/encryption/context.rb +35 -0
  113. data/lib/active_record/encryption/contexts.rb +72 -0
  114. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  115. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  116. data/lib/active_record/encryption/encryptable_record.rb +206 -0
  117. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  118. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  119. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  120. data/lib/active_record/encryption/encryptor.rb +155 -0
  121. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  122. data/lib/active_record/encryption/errors.rb +15 -0
  123. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  124. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  125. data/lib/active_record/encryption/key.rb +28 -0
  126. data/lib/active_record/encryption/key_generator.rb +42 -0
  127. data/lib/active_record/encryption/key_provider.rb +46 -0
  128. data/lib/active_record/encryption/message.rb +33 -0
  129. data/lib/active_record/encryption/message_serializer.rb +90 -0
  130. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  131. data/lib/active_record/encryption/properties.rb +76 -0
  132. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  133. data/lib/active_record/encryption/scheme.rb +99 -0
  134. data/lib/active_record/encryption.rb +55 -0
  135. data/lib/active_record/enum.rb +50 -43
  136. data/lib/active_record/errors.rb +67 -4
  137. data/lib/active_record/explain_registry.rb +11 -6
  138. data/lib/active_record/explain_subscriber.rb +1 -1
  139. data/lib/active_record/fixture_set/file.rb +15 -1
  140. data/lib/active_record/fixture_set/table_row.rb +41 -6
  141. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  142. data/lib/active_record/fixtures.rb +20 -23
  143. data/lib/active_record/future_result.rb +139 -0
  144. data/lib/active_record/gem_version.rb +5 -5
  145. data/lib/active_record/inheritance.rb +55 -17
  146. data/lib/active_record/insert_all.rb +80 -14
  147. data/lib/active_record/integration.rb +4 -3
  148. data/lib/active_record/internal_metadata.rb +1 -5
  149. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  150. data/lib/active_record/locking/optimistic.rb +36 -21
  151. data/lib/active_record/locking/pessimistic.rb +10 -4
  152. data/lib/active_record/log_subscriber.rb +23 -7
  153. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  154. data/lib/active_record/middleware/database_selector.rb +18 -6
  155. data/lib/active_record/middleware/shard_selector.rb +60 -0
  156. data/lib/active_record/migration/command_recorder.rb +8 -9
  157. data/lib/active_record/migration/compatibility.rb +93 -46
  158. data/lib/active_record/migration/join_table.rb +1 -1
  159. data/lib/active_record/migration.rb +167 -87
  160. data/lib/active_record/model_schema.rb +58 -59
  161. data/lib/active_record/nested_attributes.rb +13 -12
  162. data/lib/active_record/no_touching.rb +3 -3
  163. data/lib/active_record/null_relation.rb +2 -6
  164. data/lib/active_record/persistence.rb +231 -61
  165. data/lib/active_record/query_cache.rb +2 -2
  166. data/lib/active_record/query_logs.rb +149 -0
  167. data/lib/active_record/querying.rb +16 -6
  168. data/lib/active_record/railtie.rb +136 -22
  169. data/lib/active_record/railties/controller_runtime.rb +4 -5
  170. data/lib/active_record/railties/databases.rake +78 -136
  171. data/lib/active_record/readonly_attributes.rb +11 -0
  172. data/lib/active_record/reflection.rb +80 -49
  173. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  174. data/lib/active_record/relation/batches.rb +6 -6
  175. data/lib/active_record/relation/calculations.rb +92 -60
  176. data/lib/active_record/relation/delegation.rb +7 -7
  177. data/lib/active_record/relation/finder_methods.rb +31 -35
  178. data/lib/active_record/relation/merger.rb +20 -13
  179. data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -1
  180. data/lib/active_record/relation/predicate_builder.rb +1 -6
  181. data/lib/active_record/relation/query_attribute.rb +28 -11
  182. data/lib/active_record/relation/query_methods.rb +304 -68
  183. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  184. data/lib/active_record/relation/spawn_methods.rb +2 -2
  185. data/lib/active_record/relation/where_clause.rb +10 -19
  186. data/lib/active_record/relation.rb +189 -88
  187. data/lib/active_record/result.rb +23 -11
  188. data/lib/active_record/runtime_registry.rb +9 -13
  189. data/lib/active_record/sanitization.rb +17 -12
  190. data/lib/active_record/schema.rb +38 -23
  191. data/lib/active_record/schema_dumper.rb +29 -19
  192. data/lib/active_record/schema_migration.rb +4 -4
  193. data/lib/active_record/scoping/default.rb +60 -13
  194. data/lib/active_record/scoping/named.rb +3 -11
  195. data/lib/active_record/scoping.rb +64 -34
  196. data/lib/active_record/serialization.rb +6 -1
  197. data/lib/active_record/signed_id.rb +3 -3
  198. data/lib/active_record/store.rb +2 -2
  199. data/lib/active_record/suppressor.rb +11 -15
  200. data/lib/active_record/table_metadata.rb +6 -2
  201. data/lib/active_record/tasks/database_tasks.rb +127 -60
  202. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  203. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
  204. data/lib/active_record/test_databases.rb +1 -1
  205. data/lib/active_record/test_fixtures.rb +9 -6
  206. data/lib/active_record/timestamp.rb +3 -4
  207. data/lib/active_record/transactions.rb +12 -17
  208. data/lib/active_record/translation.rb +3 -3
  209. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  210. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  211. data/lib/active_record/type/internal/timezone.rb +2 -2
  212. data/lib/active_record/type/serialized.rb +9 -5
  213. data/lib/active_record/type/type_map.rb +17 -20
  214. data/lib/active_record/type.rb +1 -2
  215. data/lib/active_record/validations/associated.rb +4 -4
  216. data/lib/active_record/validations/presence.rb +2 -2
  217. data/lib/active_record/validations/uniqueness.rb +4 -4
  218. data/lib/active_record/version.rb +1 -1
  219. data/lib/active_record.rb +225 -27
  220. data/lib/arel/attributes/attribute.rb +0 -8
  221. data/lib/arel/crud.rb +28 -22
  222. data/lib/arel/delete_manager.rb +18 -4
  223. data/lib/arel/filter_predications.rb +9 -0
  224. data/lib/arel/insert_manager.rb +2 -3
  225. data/lib/arel/nodes/and.rb +4 -0
  226. data/lib/arel/nodes/casted.rb +1 -1
  227. data/lib/arel/nodes/delete_statement.rb +12 -13
  228. data/lib/arel/nodes/filter.rb +10 -0
  229. data/lib/arel/nodes/function.rb +1 -0
  230. data/lib/arel/nodes/insert_statement.rb +2 -2
  231. data/lib/arel/nodes/select_core.rb +2 -2
  232. data/lib/arel/nodes/select_statement.rb +2 -2
  233. data/lib/arel/nodes/update_statement.rb +8 -3
  234. data/lib/arel/nodes.rb +1 -0
  235. data/lib/arel/predications.rb +11 -3
  236. data/lib/arel/select_manager.rb +10 -4
  237. data/lib/arel/table.rb +0 -1
  238. data/lib/arel/tree_manager.rb +0 -12
  239. data/lib/arel/update_manager.rb +18 -4
  240. data/lib/arel/visitors/dot.rb +80 -90
  241. data/lib/arel/visitors/mysql.rb +8 -2
  242. data/lib/arel/visitors/postgresql.rb +0 -10
  243. data/lib/arel/visitors/to_sql.rb +58 -2
  244. data/lib/arel.rb +2 -1
  245. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  246. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  247. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  248. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  249. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  250. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  251. metadata +53 -9
@@ -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
@@ -205,16 +213,11 @@ module ActiveRecord
205
213
 
206
214
  private
207
215
  def type_casted_binds(binds)
208
- case binds.first
209
- when Array
210
- binds.map { |column, value| type_cast(value, column) }
211
- else
212
- binds.map do |value|
213
- if ActiveModel::Attribute === value
214
- type_cast(value.value_for_database)
215
- else
216
- type_cast(value)
217
- end
216
+ binds.map do |value|
217
+ if ActiveModel::Attribute === value
218
+ type_cast(value.value_for_database)
219
+ else
220
+ type_cast(value)
218
221
  end
219
222
  end
220
223
  end
@@ -222,39 +225,6 @@ module ActiveRecord
222
225
  def lookup_cast_type(sql_type)
223
226
  type_map.lookup(sql_type)
224
227
  end
225
-
226
- def _quote(value)
227
- case value
228
- when String, Symbol, ActiveSupport::Multibyte::Chars
229
- "'#{quote_string(value.to_s)}'"
230
- when true then quoted_true
231
- when false then quoted_false
232
- when nil then "NULL"
233
- # BigDecimals need to be put in a non-normalized form and quoted.
234
- when BigDecimal then value.to_s("F")
235
- when Numeric, ActiveSupport::Duration then value.to_s
236
- when Type::Binary::Data then quoted_binary(value)
237
- when Type::Time::Value then "'#{quoted_time(value)}'"
238
- when Date, Time then "'#{quoted_date(value)}'"
239
- when Class then "'#{value}'"
240
- else raise TypeError, "can't quote #{value.class.name}"
241
- end
242
- end
243
-
244
- def _type_cast(value)
245
- case value
246
- when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
247
- value.to_s
248
- when true then unquoted_true
249
- when false then unquoted_false
250
- # BigDecimals need to be put in a non-normalized form and quoted.
251
- when BigDecimal then value.to_s("F")
252
- when nil, Numeric, String then value
253
- when Type::Time::Value then quoted_time(value)
254
- when Date, Time then quoted_date(value)
255
- else raise TypeError, "can't cast #{value.class.name}"
256
- end
257
- end
258
228
  end
259
229
  end
260
230
  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"
@@ -406,14 +411,7 @@ module ActiveRecord
406
411
  name = name.to_s
407
412
  type = type.to_sym if type
408
413
 
409
- if @columns_hash[name]
410
- if @columns_hash[name].primary_key?
411
- raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
412
- else
413
- raise ArgumentError, "you can't define an already defined column '#{name}'."
414
- end
415
- end
416
-
414
+ raise_on_duplicate_column(name)
417
415
  @columns_hash[name] = new_column_definition(name, type, **options)
418
416
 
419
417
  if index
@@ -438,12 +436,12 @@ module ActiveRecord
438
436
  indexes << [column_name, options]
439
437
  end
440
438
 
441
- def foreign_key(table_name, **options) # :nodoc:
442
- foreign_keys << [table_name, options]
439
+ def foreign_key(to_table, **options)
440
+ foreign_keys << new_foreign_key_definition(to_table, options)
443
441
  end
444
442
 
445
443
  def check_constraint(expression, **options)
446
- check_constraints << [expression, options]
444
+ check_constraints << new_check_constraint_definition(expression, options)
447
445
  end
448
446
 
449
447
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
@@ -480,11 +478,31 @@ module ActiveRecord
480
478
  type = integer_like_primary_key_type(type, options)
481
479
  end
482
480
  type = aliased_types(type.to_s, type)
481
+
482
+ if @conn.supports_datetime_with_precision?
483
+ if type == :datetime && !options.key?(:precision)
484
+ options[:precision] = 6
485
+ end
486
+ end
487
+
483
488
  options[:primary_key] ||= type == :primary_key
484
489
  options[:null] = false if options[:primary_key]
485
490
  create_column_definition(name, type, options)
486
491
  end
487
492
 
493
+ def new_foreign_key_definition(to_table, options) # :nodoc:
494
+ prefix = ActiveRecord::Base.table_name_prefix
495
+ suffix = ActiveRecord::Base.table_name_suffix
496
+ to_table = "#{prefix}#{to_table}#{suffix}"
497
+ options = @conn.foreign_key_options(name, to_table, options)
498
+ ForeignKeyDefinition.new(name, to_table, options)
499
+ end
500
+
501
+ def new_check_constraint_definition(expression, options) # :nodoc:
502
+ options = @conn.check_constraint_options(name, expression, options)
503
+ CheckConstraintDefinition.new(name, expression, options)
504
+ end
505
+
488
506
  private
489
507
  def create_column_definition(name, type, options)
490
508
  ColumnDefinition.new(name, type, options)
@@ -501,6 +519,16 @@ module ActiveRecord
501
519
  def integer_like_primary_key_type(type, options)
502
520
  type
503
521
  end
522
+
523
+ def raise_on_duplicate_column(name)
524
+ if @columns_hash[name]
525
+ if @columns_hash[name].primary_key?
526
+ raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
527
+ else
528
+ raise ArgumentError, "you can't define an already defined column '#{name}'."
529
+ end
530
+ end
531
+ end
504
532
  end
505
533
 
506
534
  class AlterTable # :nodoc:
@@ -520,7 +548,7 @@ module ActiveRecord
520
548
  def name; @td.name; end
521
549
 
522
550
  def add_foreign_key(to_table, options)
523
- @foreign_key_adds << ForeignKeyDefinition.new(name, to_table, options)
551
+ @foreign_key_adds << @td.new_foreign_key_definition(to_table, options)
524
552
  end
525
553
 
526
554
  def drop_foreign_key(name)
@@ -528,7 +556,7 @@ module ActiveRecord
528
556
  end
529
557
 
530
558
  def add_check_constraint(expression, options)
531
- @check_constraint_adds << CheckConstraintDefinition.new(name, expression, options)
559
+ @check_constraint_adds << @td.new_check_constraint_definition(expression, options)
532
560
  end
533
561
 
534
562
  def drop_check_constraint(constraint_name)
@@ -572,6 +600,7 @@ module ActiveRecord
572
600
  # t.time
573
601
  # t.date
574
602
  # t.binary
603
+ # t.blob
575
604
  # t.boolean
576
605
  # t.foreign_key
577
606
  # t.json
@@ -636,8 +665,8 @@ module ActiveRecord
636
665
  # end
637
666
  #
638
667
  # See {connection.index_exists?}[rdoc-ref:SchemaStatements#index_exists?]
639
- def index_exists?(column_name, options = {})
640
- @base.index_exists?(name, column_name, options)
668
+ def index_exists?(column_name, **options)
669
+ @base.index_exists?(name, column_name, **options)
641
670
  end
642
671
 
643
672
  # Renames the given index on the table.
@@ -789,8 +818,8 @@ module ActiveRecord
789
818
  # t.check_constraint("price > 0", name: "price_check")
790
819
  #
791
820
  # See {connection.add_check_constraint}[rdoc-ref:SchemaStatements#add_check_constraint]
792
- def check_constraint(*args)
793
- @base.add_check_constraint(name, *args)
821
+ def check_constraint(*args, **options)
822
+ @base.add_check_constraint(name, *args, **options)
794
823
  end
795
824
 
796
825
  # Removes the given check constraint from the table.
@@ -798,8 +827,8 @@ module ActiveRecord
798
827
  # t.remove_check_constraint(name: "price_check")
799
828
  #
800
829
  # See {connection.remove_check_constraint}[rdoc-ref:SchemaStatements#remove_check_constraint]
801
- def remove_check_constraint(*args)
802
- @base.remove_check_constraint(name, *args)
830
+ def remove_check_constraint(*args, **options)
831
+ @base.remove_check_constraint(name, *args, **options)
803
832
  end
804
833
  end
805
834
  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)