activerecord 6.1.4 → 7.0.0.rc1

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 (234) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1049 -977
  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/preloader/association.rb +187 -55
  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 +90 -82
  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 +66 -12
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +13 -14
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +6 -21
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +2 -2
  47. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  48. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
  51. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +34 -9
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +69 -18
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +97 -81
  61. data/lib/active_record/connection_adapters/column.rb +4 -0
  62. data/lib/active_record/connection_adapters/mysql/database_statements.rb +35 -23
  63. data/lib/active_record/connection_adapters/mysql/quoting.rb +35 -21
  64. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +4 -1
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  66. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  67. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
  68. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
  69. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  72. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  73. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  76. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  77. data/lib/active_record/connection_adapters/postgresql/quoting.rb +50 -50
  78. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  79. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  80. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
  81. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  82. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +27 -16
  83. data/lib/active_record/connection_adapters/postgresql_adapter.rb +205 -105
  84. data/lib/active_record/connection_adapters/schema_cache.rb +29 -4
  85. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
  86. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +15 -16
  87. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
  88. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
  89. data/lib/active_record/connection_adapters.rb +6 -5
  90. data/lib/active_record/connection_handling.rb +47 -53
  91. data/lib/active_record/core.rb +122 -132
  92. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  93. data/lib/active_record/database_configurations/database_config.rb +12 -9
  94. data/lib/active_record/database_configurations/hash_config.rb +63 -5
  95. data/lib/active_record/database_configurations/url_config.rb +2 -2
  96. data/lib/active_record/database_configurations.rb +16 -32
  97. data/lib/active_record/delegated_type.rb +52 -11
  98. data/lib/active_record/destroy_association_async_job.rb +1 -1
  99. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  100. data/lib/active_record/dynamic_matchers.rb +1 -1
  101. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  102. data/lib/active_record/encryption/cipher.rb +53 -0
  103. data/lib/active_record/encryption/config.rb +44 -0
  104. data/lib/active_record/encryption/configurable.rb +61 -0
  105. data/lib/active_record/encryption/context.rb +35 -0
  106. data/lib/active_record/encryption/contexts.rb +72 -0
  107. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  108. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  109. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  110. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  111. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  112. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  113. data/lib/active_record/encryption/encryptor.rb +155 -0
  114. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  115. data/lib/active_record/encryption/errors.rb +15 -0
  116. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  117. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  118. data/lib/active_record/encryption/key.rb +28 -0
  119. data/lib/active_record/encryption/key_generator.rb +42 -0
  120. data/lib/active_record/encryption/key_provider.rb +46 -0
  121. data/lib/active_record/encryption/message.rb +33 -0
  122. data/lib/active_record/encryption/message_serializer.rb +90 -0
  123. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  124. data/lib/active_record/encryption/properties.rb +76 -0
  125. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  126. data/lib/active_record/encryption/scheme.rb +99 -0
  127. data/lib/active_record/encryption.rb +55 -0
  128. data/lib/active_record/enum.rb +49 -42
  129. data/lib/active_record/errors.rb +67 -4
  130. data/lib/active_record/explain_registry.rb +11 -6
  131. data/lib/active_record/fixture_set/file.rb +15 -1
  132. data/lib/active_record/fixture_set/table_row.rb +41 -6
  133. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  134. data/lib/active_record/fixtures.rb +17 -20
  135. data/lib/active_record/future_result.rb +139 -0
  136. data/lib/active_record/gem_version.rb +4 -4
  137. data/lib/active_record/inheritance.rb +55 -17
  138. data/lib/active_record/insert_all.rb +80 -14
  139. data/lib/active_record/integration.rb +4 -3
  140. data/lib/active_record/internal_metadata.rb +3 -5
  141. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  142. data/lib/active_record/locking/optimistic.rb +10 -9
  143. data/lib/active_record/locking/pessimistic.rb +9 -3
  144. data/lib/active_record/log_subscriber.rb +14 -3
  145. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  146. data/lib/active_record/middleware/database_selector.rb +8 -3
  147. data/lib/active_record/middleware/shard_selector.rb +60 -0
  148. data/lib/active_record/migration/command_recorder.rb +4 -4
  149. data/lib/active_record/migration/compatibility.rb +83 -1
  150. data/lib/active_record/migration/join_table.rb +1 -1
  151. data/lib/active_record/migration.rb +109 -79
  152. data/lib/active_record/model_schema.rb +45 -58
  153. data/lib/active_record/nested_attributes.rb +13 -12
  154. data/lib/active_record/no_touching.rb +3 -3
  155. data/lib/active_record/null_relation.rb +2 -6
  156. data/lib/active_record/persistence.rb +219 -52
  157. data/lib/active_record/query_cache.rb +2 -2
  158. data/lib/active_record/query_logs.rb +138 -0
  159. data/lib/active_record/querying.rb +15 -5
  160. data/lib/active_record/railtie.rb +127 -17
  161. data/lib/active_record/railties/controller_runtime.rb +1 -1
  162. data/lib/active_record/railties/databases.rake +66 -129
  163. data/lib/active_record/readonly_attributes.rb +11 -0
  164. data/lib/active_record/reflection.rb +67 -50
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  166. data/lib/active_record/relation/batches.rb +3 -3
  167. data/lib/active_record/relation/calculations.rb +40 -36
  168. data/lib/active_record/relation/delegation.rb +6 -6
  169. data/lib/active_record/relation/finder_methods.rb +31 -35
  170. data/lib/active_record/relation/merger.rb +20 -13
  171. data/lib/active_record/relation/predicate_builder.rb +1 -6
  172. data/lib/active_record/relation/query_attribute.rb +5 -11
  173. data/lib/active_record/relation/query_methods.rb +235 -61
  174. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  175. data/lib/active_record/relation/spawn_methods.rb +2 -2
  176. data/lib/active_record/relation/where_clause.rb +10 -19
  177. data/lib/active_record/relation.rb +171 -84
  178. data/lib/active_record/result.rb +17 -7
  179. data/lib/active_record/runtime_registry.rb +9 -13
  180. data/lib/active_record/sanitization.rb +11 -7
  181. data/lib/active_record/schema_dumper.rb +10 -3
  182. data/lib/active_record/schema_migration.rb +0 -4
  183. data/lib/active_record/scoping/default.rb +61 -12
  184. data/lib/active_record/scoping/named.rb +3 -11
  185. data/lib/active_record/scoping.rb +64 -34
  186. data/lib/active_record/serialization.rb +1 -1
  187. data/lib/active_record/signed_id.rb +1 -1
  188. data/lib/active_record/suppressor.rb +11 -15
  189. data/lib/active_record/tasks/database_tasks.rb +116 -58
  190. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  191. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -12
  192. data/lib/active_record/test_databases.rb +1 -1
  193. data/lib/active_record/test_fixtures.rb +4 -4
  194. data/lib/active_record/timestamp.rb +3 -4
  195. data/lib/active_record/transactions.rb +9 -14
  196. data/lib/active_record/translation.rb +2 -2
  197. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  198. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  199. data/lib/active_record/type/internal/timezone.rb +2 -2
  200. data/lib/active_record/type/serialized.rb +1 -1
  201. data/lib/active_record/type/type_map.rb +17 -20
  202. data/lib/active_record/type.rb +1 -2
  203. data/lib/active_record/validations/associated.rb +1 -1
  204. data/lib/active_record/validations/uniqueness.rb +1 -1
  205. data/lib/active_record.rb +204 -28
  206. data/lib/arel/attributes/attribute.rb +0 -8
  207. data/lib/arel/crud.rb +28 -22
  208. data/lib/arel/delete_manager.rb +18 -4
  209. data/lib/arel/filter_predications.rb +9 -0
  210. data/lib/arel/insert_manager.rb +2 -3
  211. data/lib/arel/nodes/casted.rb +1 -1
  212. data/lib/arel/nodes/delete_statement.rb +12 -13
  213. data/lib/arel/nodes/filter.rb +10 -0
  214. data/lib/arel/nodes/function.rb +1 -0
  215. data/lib/arel/nodes/insert_statement.rb +2 -2
  216. data/lib/arel/nodes/select_core.rb +2 -2
  217. data/lib/arel/nodes/select_statement.rb +2 -2
  218. data/lib/arel/nodes/update_statement.rb +8 -3
  219. data/lib/arel/nodes.rb +1 -0
  220. data/lib/arel/predications.rb +11 -3
  221. data/lib/arel/select_manager.rb +10 -4
  222. data/lib/arel/table.rb +0 -1
  223. data/lib/arel/tree_manager.rb +0 -12
  224. data/lib/arel/update_manager.rb +18 -4
  225. data/lib/arel/visitors/dot.rb +80 -90
  226. data/lib/arel/visitors/mysql.rb +8 -2
  227. data/lib/arel/visitors/postgresql.rb +0 -10
  228. data/lib/arel/visitors/to_sql.rb +58 -2
  229. data/lib/arel.rb +2 -1
  230. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  231. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  232. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  233. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  234. metadata +56 -13
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/string/access"
4
- require "digest/sha2"
4
+ require "openssl"
5
5
 
6
6
  module ActiveRecord
7
7
  module ConnectionAdapters # :nodoc:
@@ -29,7 +29,7 @@ module ActiveRecord
29
29
  table_name[0...table_alias_length].tr(".", "_")
30
30
  end
31
31
 
32
- # Returns the relation names useable to back Active Record models.
32
+ # Returns the relation names usable to back Active Record models.
33
33
  # For most adapters this means all #tables and #views.
34
34
  def data_sources
35
35
  query_values(data_source_sql, "SCHEMA")
@@ -124,6 +124,9 @@ module ActiveRecord
124
124
  # column_exists?(:suppliers, :name)
125
125
  #
126
126
  # # Check a column exists of a particular type
127
+ # #
128
+ # # This works for standard non-casted types (eg. string) but is unreliable
129
+ # # for types that may get cast to something else (eg. char, bigint).
127
130
  # column_exists?(:suppliers, :name, :string)
128
131
  #
129
132
  # # Check a column exists with a specific definition
@@ -518,24 +521,31 @@ module ActiveRecord
518
521
 
519
522
  # Add a new +type+ column named +column_name+ to +table_name+.
520
523
  #
524
+ # See {ActiveRecord::ConnectionAdapters::TableDefinition.column}[rdoc-ref:ActiveRecord::ConnectionAdapters::TableDefinition#column].
525
+ #
521
526
  # The +type+ parameter is normally one of the migrations native types,
522
527
  # which is one of the following:
523
528
  # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
524
529
  # <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:numeric</tt>,
525
530
  # <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
526
- # <tt>:binary</tt>, <tt>:boolean</tt>.
531
+ # <tt>:binary</tt>, <tt>:blob</tt>, <tt>:boolean</tt>.
527
532
  #
528
533
  # You may use a type not in this list as long as it is supported by your
529
534
  # database (for example, "polygon" in MySQL), but this will not be database
530
535
  # agnostic and should usually be avoided.
531
536
  #
532
537
  # Available options are (none of these exists by default):
538
+ # * <tt>:comment</tt> -
539
+ # Specifies the comment for the column. This option is ignored by some backends.
540
+ # * <tt>:collation</tt> -
541
+ # Specifies the collation for a <tt>:string</tt> or <tt>:text</tt> column.
542
+ # If not specified, the column will have the same collation as the table.
543
+ # * <tt>:default</tt> -
544
+ # The column's default value. Use +nil+ for +NULL+.
533
545
  # * <tt>:limit</tt> -
534
546
  # Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
535
- # and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, and <tt>:integer</tt> columns.
547
+ # and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, <tt>:blob</tt>, and <tt>:integer</tt> columns.
536
548
  # This option is ignored by some backends.
537
- # * <tt>:default</tt> -
538
- # The column's default value. Use +nil+ for +NULL+.
539
549
  # * <tt>:null</tt> -
540
550
  # Allows or disallows +NULL+ values in the column.
541
551
  # * <tt>:precision</tt> -
@@ -604,7 +614,13 @@ module ActiveRecord
604
614
  # # Ignores the method call if the column exists
605
615
  # add_column(:shapes, :triangle, 'polygon', if_not_exists: true)
606
616
  def add_column(table_name, column_name, type, **options)
607
- return if options[:if_not_exists] == true && column_exists?(table_name, column_name, type)
617
+ return if options[:if_not_exists] == true && column_exists?(table_name, column_name)
618
+
619
+ if supports_datetime_with_precision?
620
+ if type == :datetime && !options.key?(:precision)
621
+ options[:precision] = 6
622
+ end
623
+ end
608
624
 
609
625
  at = create_alter_table table_name
610
626
  at.add_column(column_name, type, **options)
@@ -629,9 +645,8 @@ module ActiveRecord
629
645
  raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)")
630
646
  end
631
647
 
632
- column_names.each do |column_name|
633
- remove_column(table_name, column_name, type, **options)
634
- end
648
+ remove_column_fragments = remove_columns_for_alter(table_name, *column_names, type: type, **options)
649
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{remove_column_fragments.join(', ')}"
635
650
  end
636
651
 
637
652
  # Removes the column from the table definition.
@@ -641,7 +656,8 @@ module ActiveRecord
641
656
  # The +type+ and +options+ parameters will be ignored if present. It can be helpful
642
657
  # to provide these in a migration's +change+ method so it can be reverted.
643
658
  # In that case, +type+ and +options+ will be used by #add_column.
644
- # Indexes on the column are automatically removed.
659
+ # Depending on the database you're using, indexes using this column may be
660
+ # automatically removed or modified to remove this column from the index.
645
661
  #
646
662
  # If the options provided include an +if_exists+ key, it will be used to check if the
647
663
  # column does not exist. This will silently ignore the migration rather than raising
@@ -766,7 +782,7 @@ module ActiveRecord
766
782
  #
767
783
  # CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
768
784
  #
769
- # Note: SQLite doesn't support index length.
785
+ # Note: only supported by MySQL
770
786
  #
771
787
  # ====== Creating an index with a sort order (desc or asc, asc is the default)
772
788
  #
@@ -901,7 +917,7 @@ module ActiveRecord
901
917
  remove_index(table_name, name: old_name)
902
918
  end
903
919
 
904
- def index_name(table_name, options) #:nodoc:
920
+ def index_name(table_name, options) # :nodoc:
905
921
  if Hash === options
906
922
  if options[:column]
907
923
  "index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
@@ -1027,6 +1043,10 @@ module ActiveRecord
1027
1043
  #
1028
1044
  # ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
1029
1045
  #
1046
+ # ====== Creating a foreign key, ignoring method call if the foreign key exists
1047
+ #
1048
+ # add_foreign_key(:articles, :authors, if_not_exists: true)
1049
+ #
1030
1050
  # ====== Creating a foreign key on a specific column
1031
1051
  #
1032
1052
  # add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
@@ -1054,10 +1074,17 @@ module ActiveRecord
1054
1074
  # Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
1055
1075
  # [<tt>:on_update</tt>]
1056
1076
  # Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
1077
+ # [<tt>:if_not_exists</tt>]
1078
+ # Specifies if the foreign key already exists to not try to re-add it. This will avoid
1079
+ # duplicate column errors.
1057
1080
  # [<tt>:validate</tt>]
1058
1081
  # (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
1082
+ # [<tt>:deferrable</tt>]
1083
+ # (PostgreSQL only) Specify whether or not the foreign key should be deferrable. Valid values are booleans or
1084
+ # +:deferred+ or +:immediate+ to specify the default behavior. Defaults to +false+.
1059
1085
  def add_foreign_key(from_table, to_table, **options)
1060
1086
  return unless supports_foreign_keys?
1087
+ return if options[:if_not_exists] == true && foreign_key_exists?(from_table, to_table)
1061
1088
 
1062
1089
  options = foreign_key_options(from_table, to_table, options)
1063
1090
  at = create_alter_table from_table
@@ -1087,12 +1114,18 @@ module ActiveRecord
1087
1114
  #
1088
1115
  # remove_foreign_key :accounts, name: :special_fk_name
1089
1116
  #
1117
+ # Checks if the foreign key exists before trying to remove it. Will silently ignore indexes that
1118
+ # don't exist.
1119
+ #
1120
+ # remove_foreign_key :accounts, :branches, if_exists: true
1121
+ #
1090
1122
  # The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key
1091
1123
  # with an addition of
1092
1124
  # [<tt>:to_table</tt>]
1093
1125
  # The name of the table that contains the referenced primary key.
1094
1126
  def remove_foreign_key(from_table, to_table = nil, **options)
1095
1127
  return unless supports_foreign_keys?
1128
+ return if options[:if_exists] == true && !foreign_key_exists?(from_table, to_table)
1096
1129
 
1097
1130
  fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
1098
1131
 
@@ -1256,6 +1289,25 @@ module ActiveRecord
1256
1289
  columns
1257
1290
  end
1258
1291
 
1292
+ def distinct_relation_for_primary_key(relation) # :nodoc:
1293
+ values = columns_for_distinct(
1294
+ visitor.compile(relation.table[relation.primary_key]),
1295
+ relation.order_values
1296
+ )
1297
+
1298
+ limited = relation.reselect(values).distinct!
1299
+ limited_ids = select_rows(limited.arel, "SQL").map(&:last)
1300
+
1301
+ if limited_ids.empty?
1302
+ relation.none!
1303
+ else
1304
+ relation.where!(relation.primary_key => limited_ids)
1305
+ end
1306
+
1307
+ relation.limit_value = relation.offset_value = nil
1308
+ relation
1309
+ end
1310
+
1259
1311
  # Adds timestamps (+created_at+ and +updated_at+) columns to +table_name+.
1260
1312
  # Additional options (like +:null+) are forwarded to #add_column.
1261
1313
  #
@@ -1277,11 +1329,10 @@ module ActiveRecord
1277
1329
  # remove_timestamps(:suppliers)
1278
1330
  #
1279
1331
  def remove_timestamps(table_name, **options)
1280
- remove_column table_name, :updated_at
1281
- remove_column table_name, :created_at
1332
+ remove_columns table_name, :updated_at, :created_at
1282
1333
  end
1283
1334
 
1284
- def update_table_definition(table_name, base) #:nodoc:
1335
+ def update_table_definition(table_name, base) # :nodoc:
1285
1336
  Table.new(table_name, base)
1286
1337
  end
1287
1338
 
@@ -1488,7 +1539,7 @@ module ActiveRecord
1488
1539
  def foreign_key_name(table_name, options)
1489
1540
  options.fetch(:name) do
1490
1541
  identifier = "#{table_name}_#{options.fetch(:column)}_fk"
1491
- hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
1542
+ hashed_identifier = OpenSSL::Digest::SHA256.hexdigest(identifier).first(10)
1492
1543
 
1493
1544
  "fk_rails_#{hashed_identifier}"
1494
1545
  end
@@ -1516,7 +1567,7 @@ module ActiveRecord
1516
1567
  options.fetch(:name) do
1517
1568
  expression = options.fetch(:expression)
1518
1569
  identifier = "#{table_name}_#{expression}_chk"
1519
- hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
1570
+ hashed_identifier = OpenSSL::Digest::SHA256.hexdigest(identifier).first(10)
1520
1571
 
1521
1572
  "chk_rails_#{hashed_identifier}"
1522
1573
  end
@@ -73,7 +73,7 @@ module ActiveRecord
73
73
  end
74
74
  end
75
75
 
76
- class NullTransaction #:nodoc:
76
+ class NullTransaction # :nodoc:
77
77
  def initialize; end
78
78
  def state; end
79
79
  def closed?; true; end
@@ -82,7 +82,7 @@ module ActiveRecord
82
82
  def add_record(record, _ = true); end
83
83
  end
84
84
 
85
- class Transaction #:nodoc:
85
+ class Transaction # :nodoc:
86
86
  attr_reader :connection, :state, :savepoint_name, :isolation_level
87
87
  attr_accessor :written
88
88
 
@@ -221,7 +221,7 @@ module ActiveRecord
221
221
  end
222
222
  end
223
223
 
224
- class TransactionManager #:nodoc:
224
+ class TransactionManager # :nodoc:
225
225
  def initialize(connection)
226
226
  @stack = []
227
227
  @connection = connection
@@ -333,26 +333,19 @@ module ActiveRecord
333
333
  # @connection still holds an open or invalid transaction, so we must not
334
334
  # put it back in the pool for reuse.
335
335
  @connection.throw_away! unless transaction.state.rolledback?
336
+ elsif Thread.current.status == "aborting" || (!completed && transaction.written)
337
+ # The transaction is still open but the block returned earlier.
338
+ #
339
+ # The block could return early because of a timeout or because the thread is aborting,
340
+ # so we are rolling back to make sure the timeout didn't caused the transaction to be
341
+ # committed incompletely.
342
+ rollback_transaction
336
343
  else
337
- if Thread.current.status == "aborting"
338
- rollback_transaction
339
- else
340
- if !completed && transaction.written
341
- ActiveSupport::Deprecation.warn(<<~EOW)
342
- Using `return`, `break` or `throw` to exit a transaction block is
343
- deprecated without replacement. If the `throw` came from
344
- `Timeout.timeout(duration)`, pass an exception class as a second
345
- argument so it doesn't use `throw` to abort its block. This results
346
- in the transaction being committed, but in the next release of Rails
347
- it will rollback.
348
- EOW
349
- end
350
- begin
351
- commit_transaction
352
- rescue Exception
353
- rollback_transaction(transaction) unless transaction.state.completed?
354
- raise
355
- end
344
+ begin
345
+ commit_transaction
346
+ rescue Exception
347
+ rollback_transaction(transaction) unless transaction.state.completed?
348
+ raise
356
349
  end
357
350
  end
358
351
  end
@@ -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