activerecord 6.0.0 → 7.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +996 -594
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +34 -34
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +22 -20
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +41 -30
  9. data/lib/active_record/associations/association.rb +106 -41
  10. data/lib/active_record/associations/association_scope.rb +30 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +69 -14
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +20 -6
  13. data/lib/active_record/associations/builder/association.rb +39 -6
  14. data/lib/active_record/associations/builder/belongs_to.rb +47 -17
  15. data/lib/active_record/associations/builder/collection_association.rb +14 -6
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -10
  17. data/lib/active_record/associations/builder/has_many.rb +7 -3
  18. data/lib/active_record/associations/builder/has_one.rb +13 -16
  19. data/lib/active_record/associations/builder/singular_association.rb +7 -3
  20. data/lib/active_record/associations/collection_association.rb +90 -53
  21. data/lib/active_record/associations/collection_proxy.rb +54 -19
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/errors.rb +265 -0
  24. data/lib/active_record/associations/foreign_association.rb +21 -1
  25. data/lib/active_record/associations/has_many_association.rb +41 -10
  26. data/lib/active_record/associations/has_many_through_association.rb +29 -12
  27. data/lib/active_record/associations/has_one_association.rb +33 -9
  28. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  29. data/lib/active_record/associations/join_dependency/join_association.rb +41 -17
  30. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  31. data/lib/active_record/associations/join_dependency.rb +97 -54
  32. data/lib/active_record/associations/nested_error.rb +47 -0
  33. data/lib/active_record/associations/preloader/association.rb +237 -54
  34. data/lib/active_record/associations/preloader/batch.rb +48 -0
  35. data/lib/active_record/associations/preloader/branch.rb +153 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +51 -17
  37. data/lib/active_record/associations/preloader.rb +55 -121
  38. data/lib/active_record/associations/singular_association.rb +16 -4
  39. data/lib/active_record/associations/through_association.rb +26 -15
  40. data/lib/active_record/associations.rb +454 -440
  41. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  42. data/lib/active_record/attribute_assignment.rb +11 -14
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +36 -11
  44. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  45. data/lib/active_record/attribute_methods/dirty.rb +75 -34
  46. data/lib/active_record/attribute_methods/primary_key.rb +53 -31
  47. data/lib/active_record/attribute_methods/query.rb +31 -22
  48. data/lib/active_record/attribute_methods/read.rb +16 -17
  49. data/lib/active_record/attribute_methods/serialization.rb +177 -35
  50. data/lib/active_record/attribute_methods/time_zone_conversion.rb +18 -15
  51. data/lib/active_record/attribute_methods/write.rb +16 -28
  52. data/lib/active_record/attribute_methods.rb +227 -100
  53. data/lib/active_record/attributes.rb +94 -56
  54. data/lib/active_record/autosave_association.rb +119 -73
  55. data/lib/active_record/base.rb +31 -21
  56. data/lib/active_record/callbacks.rb +168 -55
  57. data/lib/active_record/coders/column_serializer.rb +61 -0
  58. data/lib/active_record/coders/json.rb +1 -1
  59. data/lib/active_record/coders/yaml_column.rb +70 -25
  60. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +367 -565
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -57
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +277 -89
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +241 -69
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +122 -134
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +324 -72
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +17 -4
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +611 -211
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +425 -82
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +698 -211
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +464 -239
  76. data/lib/active_record/connection_adapters/column.rb +28 -1
  77. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  78. data/lib/active_record/connection_adapters/mysql/column.rb +2 -1
  79. data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -137
  80. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  81. data/lib/active_record/connection_adapters/mysql/quoting.rb +90 -43
  82. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +41 -7
  83. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +18 -1
  84. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +13 -4
  85. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +53 -15
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  87. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  88. data/lib/active_record/connection_adapters/mysql2_adapter.rb +127 -63
  89. data/lib/active_record/connection_adapters/pool_config.rb +83 -0
  90. data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
  91. data/lib/active_record/connection_adapters/postgresql/column.rb +54 -2
  92. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +127 -100
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +9 -5
  95. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
  97. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -15
  99. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  101. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -4
  103. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +35 -8
  106. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  110. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -4
  111. data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
  112. data/lib/active_record/connection_adapters/postgresql/quoting.rb +139 -106
  113. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -2
  114. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +98 -4
  115. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +176 -4
  116. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -1
  117. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -118
  118. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  119. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -11
  120. data/lib/active_record/connection_adapters/postgresql_adapter.rb +585 -295
  121. data/lib/active_record/connection_adapters/schema_cache.rb +399 -60
  122. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  123. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  124. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +99 -48
  125. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +80 -54
  126. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +27 -1
  127. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
  128. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  129. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +102 -24
  130. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +425 -174
  131. data/lib/active_record/connection_adapters/statement_pool.rb +7 -1
  132. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  133. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  134. data/lib/active_record/connection_adapters.rb +176 -0
  135. data/lib/active_record/connection_handling.rb +243 -115
  136. data/lib/active_record/core.rb +481 -199
  137. data/lib/active_record/counter_cache.rb +69 -32
  138. data/lib/active_record/database_configurations/connection_url_resolver.rb +107 -0
  139. data/lib/active_record/database_configurations/database_config.rb +77 -10
  140. data/lib/active_record/database_configurations/hash_config.rb +148 -26
  141. data/lib/active_record/database_configurations/url_config.rb +44 -45
  142. data/lib/active_record/database_configurations.rb +190 -114
  143. data/lib/active_record/delegated_type.rb +279 -0
  144. data/lib/active_record/deprecator.rb +7 -0
  145. data/lib/active_record/destroy_association_async_job.rb +38 -0
  146. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  147. data/lib/active_record/dynamic_matchers.rb +5 -6
  148. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  149. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  150. data/lib/active_record/encryption/cipher.rb +53 -0
  151. data/lib/active_record/encryption/config.rb +68 -0
  152. data/lib/active_record/encryption/configurable.rb +60 -0
  153. data/lib/active_record/encryption/context.rb +42 -0
  154. data/lib/active_record/encryption/contexts.rb +76 -0
  155. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  156. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  157. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  158. data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
  159. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  160. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  161. data/lib/active_record/encryption/encryptor.rb +171 -0
  162. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  163. data/lib/active_record/encryption/errors.rb +15 -0
  164. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  165. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  166. data/lib/active_record/encryption/key.rb +28 -0
  167. data/lib/active_record/encryption/key_generator.rb +53 -0
  168. data/lib/active_record/encryption/key_provider.rb +46 -0
  169. data/lib/active_record/encryption/message.rb +33 -0
  170. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  171. data/lib/active_record/encryption/message_serializer.rb +96 -0
  172. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  173. data/lib/active_record/encryption/properties.rb +76 -0
  174. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  175. data/lib/active_record/encryption/scheme.rb +100 -0
  176. data/lib/active_record/encryption.rb +58 -0
  177. data/lib/active_record/enum.rb +224 -73
  178. data/lib/active_record/errors.rb +254 -36
  179. data/lib/active_record/explain.rb +30 -17
  180. data/lib/active_record/explain_registry.rb +11 -6
  181. data/lib/active_record/explain_subscriber.rb +2 -2
  182. data/lib/active_record/fixture_set/file.rb +22 -15
  183. data/lib/active_record/fixture_set/model_metadata.rb +15 -6
  184. data/lib/active_record/fixture_set/render_context.rb +3 -1
  185. data/lib/active_record/fixture_set/table_row.rb +88 -16
  186. data/lib/active_record/fixture_set/table_rows.rb +4 -5
  187. data/lib/active_record/fixtures.rb +229 -116
  188. data/lib/active_record/future_result.rb +178 -0
  189. data/lib/active_record/gem_version.rb +4 -4
  190. data/lib/active_record/inheritance.rb +121 -48
  191. data/lib/active_record/insert_all.rb +178 -29
  192. data/lib/active_record/integration.rb +16 -14
  193. data/lib/active_record/internal_metadata.rb +132 -21
  194. data/lib/active_record/legacy_yaml_adapter.rb +3 -36
  195. data/lib/active_record/locking/optimistic.rb +64 -33
  196. data/lib/active_record/locking/pessimistic.rb +21 -8
  197. data/lib/active_record/log_subscriber.rb +61 -30
  198. data/lib/active_record/marshalling.rb +59 -0
  199. data/lib/active_record/message_pack.rb +124 -0
  200. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  201. data/lib/active_record/middleware/database_selector/resolver.rb +19 -19
  202. data/lib/active_record/middleware/database_selector.rb +25 -13
  203. data/lib/active_record/middleware/shard_selector.rb +62 -0
  204. data/lib/active_record/migration/command_recorder.rb +160 -55
  205. data/lib/active_record/migration/compatibility.rb +286 -43
  206. data/lib/active_record/migration/default_strategy.rb +22 -0
  207. data/lib/active_record/migration/execution_strategy.rb +19 -0
  208. data/lib/active_record/migration/join_table.rb +1 -2
  209. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  210. data/lib/active_record/migration.rb +421 -193
  211. data/lib/active_record/model_schema.rb +217 -125
  212. data/lib/active_record/nested_attributes.rb +62 -27
  213. data/lib/active_record/no_touching.rb +4 -4
  214. data/lib/active_record/normalization.rb +163 -0
  215. data/lib/active_record/persistence.rb +322 -319
  216. data/lib/active_record/promise.rb +84 -0
  217. data/lib/active_record/query_cache.rb +18 -15
  218. data/lib/active_record/query_logs.rb +193 -0
  219. data/lib/active_record/query_logs_formatter.rb +41 -0
  220. data/lib/active_record/querying.rb +54 -14
  221. data/lib/active_record/railtie.rb +250 -72
  222. data/lib/active_record/railties/console_sandbox.rb +2 -4
  223. data/lib/active_record/railties/controller_runtime.rb +25 -11
  224. data/lib/active_record/railties/databases.rake +312 -197
  225. data/lib/active_record/railties/job_runtime.rb +23 -0
  226. data/lib/active_record/readonly_attributes.rb +45 -3
  227. data/lib/active_record/reflection.rb +389 -146
  228. data/lib/active_record/relation/batches/batch_enumerator.rb +61 -16
  229. data/lib/active_record/relation/batches.rb +214 -73
  230. data/lib/active_record/relation/calculations.rb +379 -124
  231. data/lib/active_record/relation/delegation.rb +36 -23
  232. data/lib/active_record/relation/finder_methods.rb +159 -49
  233. data/lib/active_record/relation/from_clause.rb +5 -1
  234. data/lib/active_record/relation/merger.rb +41 -33
  235. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -11
  236. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -7
  237. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +20 -13
  238. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  239. data/lib/active_record/relation/predicate_builder.rb +79 -53
  240. data/lib/active_record/relation/query_attribute.rb +30 -12
  241. data/lib/active_record/relation/query_methods.rb +1156 -279
  242. data/lib/active_record/relation/record_fetch_warning.rb +12 -11
  243. data/lib/active_record/relation/spawn_methods.rb +10 -9
  244. data/lib/active_record/relation/where_clause.rb +100 -66
  245. data/lib/active_record/relation.rb +829 -194
  246. data/lib/active_record/result.rb +76 -56
  247. data/lib/active_record/runtime_registry.rb +71 -13
  248. data/lib/active_record/sanitization.rb +86 -47
  249. data/lib/active_record/schema.rb +39 -23
  250. data/lib/active_record/schema_dumper.rb +140 -33
  251. data/lib/active_record/schema_migration.rb +74 -29
  252. data/lib/active_record/scoping/default.rb +73 -19
  253. data/lib/active_record/scoping/named.rb +10 -28
  254. data/lib/active_record/scoping.rb +65 -35
  255. data/lib/active_record/secure_password.rb +60 -0
  256. data/lib/active_record/secure_token.rb +34 -8
  257. data/lib/active_record/serialization.rb +11 -4
  258. data/lib/active_record/signed_id.rb +138 -0
  259. data/lib/active_record/statement_cache.rb +26 -10
  260. data/lib/active_record/store.rb +19 -14
  261. data/lib/active_record/suppressor.rb +15 -17
  262. data/lib/active_record/table_metadata.rb +46 -36
  263. data/lib/active_record/tasks/database_tasks.rb +371 -205
  264. data/lib/active_record/tasks/mysql_database_tasks.rb +43 -36
  265. data/lib/active_record/tasks/postgresql_database_tasks.rb +54 -41
  266. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -13
  267. data/lib/active_record/test_databases.rb +5 -4
  268. data/lib/active_record/test_fixtures.rb +189 -104
  269. data/lib/active_record/testing/query_assertions.rb +121 -0
  270. data/lib/active_record/timestamp.rb +35 -25
  271. data/lib/active_record/token_for.rb +123 -0
  272. data/lib/active_record/touch_later.rb +31 -27
  273. data/lib/active_record/transaction.rb +132 -0
  274. data/lib/active_record/transactions.rb +131 -99
  275. data/lib/active_record/translation.rb +3 -5
  276. data/lib/active_record/type/adapter_specific_registry.rb +33 -18
  277. data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
  278. data/lib/active_record/type/internal/timezone.rb +7 -2
  279. data/lib/active_record/type/serialized.rb +11 -6
  280. data/lib/active_record/type/time.rb +14 -0
  281. data/lib/active_record/type/type_map.rb +17 -21
  282. data/lib/active_record/type/unsigned_integer.rb +0 -1
  283. data/lib/active_record/type.rb +7 -2
  284. data/lib/active_record/type_caster/connection.rb +4 -5
  285. data/lib/active_record/type_caster/map.rb +8 -5
  286. data/lib/active_record/validations/absence.rb +1 -1
  287. data/lib/active_record/validations/associated.rb +13 -8
  288. data/lib/active_record/validations/numericality.rb +36 -0
  289. data/lib/active_record/validations/presence.rb +5 -28
  290. data/lib/active_record/validations/uniqueness.rb +88 -18
  291. data/lib/active_record/validations.rb +15 -8
  292. data/lib/active_record/version.rb +1 -1
  293. data/lib/active_record.rb +446 -40
  294. data/lib/arel/alias_predication.rb +1 -1
  295. data/lib/arel/attributes/attribute.rb +4 -8
  296. data/lib/arel/collectors/bind.rb +8 -1
  297. data/lib/arel/collectors/composite.rb +15 -0
  298. data/lib/arel/collectors/sql_string.rb +7 -0
  299. data/lib/arel/collectors/substitute_binds.rb +7 -0
  300. data/lib/arel/crud.rb +30 -22
  301. data/lib/arel/delete_manager.rb +23 -4
  302. data/lib/arel/errors.rb +10 -0
  303. data/lib/arel/factory_methods.rb +4 -0
  304. data/lib/arel/filter_predications.rb +9 -0
  305. data/lib/arel/insert_manager.rb +2 -3
  306. data/lib/arel/nodes/binary.rb +82 -9
  307. data/lib/arel/nodes/bind_param.rb +8 -0
  308. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  309. data/lib/arel/nodes/casted.rb +22 -10
  310. data/lib/arel/nodes/cte.rb +36 -0
  311. data/lib/arel/nodes/delete_statement.rb +14 -13
  312. data/lib/arel/nodes/equality.rb +6 -9
  313. data/lib/arel/nodes/filter.rb +10 -0
  314. data/lib/arel/nodes/fragments.rb +35 -0
  315. data/lib/arel/nodes/function.rb +1 -0
  316. data/lib/arel/nodes/grouping.rb +3 -0
  317. data/lib/arel/nodes/homogeneous_in.rb +68 -0
  318. data/lib/arel/nodes/in.rb +8 -1
  319. data/lib/arel/nodes/infix_operation.rb +13 -1
  320. data/lib/arel/nodes/insert_statement.rb +2 -2
  321. data/lib/arel/nodes/join_source.rb +1 -1
  322. data/lib/arel/nodes/leading_join.rb +8 -0
  323. data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
  324. data/lib/arel/nodes/node.rb +122 -11
  325. data/lib/arel/nodes/ordering.rb +27 -0
  326. data/lib/arel/nodes/select_core.rb +2 -2
  327. data/lib/arel/nodes/select_statement.rb +2 -2
  328. data/lib/arel/nodes/sql_literal.rb +16 -0
  329. data/lib/arel/nodes/table_alias.rb +11 -3
  330. data/lib/arel/nodes/unary.rb +0 -1
  331. data/lib/arel/nodes/update_statement.rb +11 -4
  332. data/lib/arel/nodes.rb +10 -3
  333. data/lib/arel/predications.rb +31 -28
  334. data/lib/arel/select_manager.rb +18 -9
  335. data/lib/arel/table.rb +21 -10
  336. data/lib/arel/tree_manager.rb +8 -15
  337. data/lib/arel/update_manager.rb +25 -5
  338. data/lib/arel/visitors/dot.rb +94 -90
  339. data/lib/arel/visitors/mysql.rb +34 -6
  340. data/lib/arel/visitors/postgresql.rb +5 -16
  341. data/lib/arel/visitors/sqlite.rb +25 -1
  342. data/lib/arel/visitors/to_sql.rb +227 -81
  343. data/lib/arel/visitors/visitor.rb +2 -3
  344. data/lib/arel/visitors.rb +0 -7
  345. data/lib/arel.rb +37 -15
  346. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  347. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  348. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  349. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  350. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +6 -1
  351. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  352. data/lib/rails/generators/active_record/migration.rb +9 -3
  353. data/lib/rails/generators/active_record/model/USAGE +113 -0
  354. data/lib/rails/generators/active_record/model/model_generator.rb +49 -4
  355. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  356. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  357. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  358. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  359. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  360. metadata +117 -30
  361. data/lib/active_record/attribute_decorators.rb +0 -90
  362. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  363. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  364. data/lib/active_record/define_callbacks.rb +0 -22
  365. data/lib/active_record/null_relation.rb +0 -68
  366. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  367. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  368. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  369. data/lib/arel/attributes.rb +0 -22
  370. data/lib/arel/visitors/depth_first.rb +0 -204
  371. data/lib/arel/visitors/ibm_db.rb +0 -34
  372. data/lib/arel/visitors/informix.rb +0 -62
  373. data/lib/arel/visitors/mssql.rb +0 -157
  374. data/lib/arel/visitors/oracle.rb +0 -159
  375. data/lib/arel/visitors/oracle12.rb +0 -66
  376. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -1,14 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/digest"
4
+
3
5
  module ActiveRecord
4
6
  module ConnectionAdapters
7
+ # = Active Record Connection Adapters Transaction State
5
8
  class TransactionState
6
9
  def initialize(state = nil)
7
10
  @state = state
8
- @children = []
11
+ @children = nil
9
12
  end
10
13
 
11
14
  def add_child(state)
15
+ @children ||= []
12
16
  @children << state
13
17
  end
14
18
 
@@ -32,6 +36,10 @@ module ActiveRecord
32
36
  @state == :fully_rolledback
33
37
  end
34
38
 
39
+ def invalidated?
40
+ @state == :invalidated
41
+ end
42
+
35
43
  def fully_completed?
36
44
  completed?
37
45
  end
@@ -41,15 +49,20 @@ module ActiveRecord
41
49
  end
42
50
 
43
51
  def rollback!
44
- @children.each { |c| c.rollback! }
52
+ @children&.each { |c| c.rollback! }
45
53
  @state = :rolledback
46
54
  end
47
55
 
48
56
  def full_rollback!
49
- @children.each { |c| c.rollback! }
57
+ @children&.each { |c| c.rollback! }
50
58
  @state = :fully_rolledback
51
59
  end
52
60
 
61
+ def invalidate!
62
+ @children&.each { |c| c.invalidate! }
63
+ @state = :invalidated
64
+ end
65
+
53
66
  def commit!
54
67
  @state = :committed
55
68
  end
@@ -63,86 +76,334 @@ module ActiveRecord
63
76
  end
64
77
  end
65
78
 
66
- class NullTransaction #:nodoc:
67
- def initialize; end
79
+ class TransactionInstrumenter
80
+ def initialize(payload = {})
81
+ @handle = nil
82
+ @started = false
83
+ @payload = nil
84
+ @base_payload = payload
85
+ end
86
+
87
+ class InstrumentationNotStartedError < ActiveRecordError; end
88
+ class InstrumentationAlreadyStartedError < ActiveRecordError; end
89
+
90
+ def start
91
+ raise InstrumentationAlreadyStartedError.new("Called start on an already started transaction") if @started
92
+ @started = true
93
+
94
+ ActiveSupport::Notifications.instrument("start_transaction.active_record", @base_payload)
95
+
96
+ @payload = @base_payload.dup # We dup because the payload for a given event is mutated later to add the outcome.
97
+ @handle = ActiveSupport::Notifications.instrumenter.build_handle("transaction.active_record", @payload)
98
+ @handle.start
99
+ end
100
+
101
+ def finish(outcome)
102
+ raise InstrumentationNotStartedError.new("Called finish on a transaction that hasn't started") unless @started
103
+ @started = false
104
+
105
+ @payload[:outcome] = outcome
106
+ @handle.finish
107
+ end
108
+ end
109
+
110
+ class NullTransaction # :nodoc:
68
111
  def state; end
69
112
  def closed?; true; end
70
113
  def open?; false; end
71
114
  def joinable?; false; end
72
- def add_record(record); end
115
+ def add_record(record, _ = true); end
116
+ def restartable?; false; end
117
+ def dirty?; false; end
118
+ def dirty!; end
119
+ def invalidated?; false; end
120
+ def invalidate!; end
121
+ def materialized?; false; end
122
+ def before_commit; yield; end
123
+ def after_commit; yield; end
124
+ def after_rollback; end
125
+ def user_transaction; ActiveRecord::Transaction::NULL_TRANSACTION; end
73
126
  end
74
127
 
75
- class Transaction #:nodoc:
76
- attr_reader :connection, :state, :records, :savepoint_name, :isolation_level
128
+ class Transaction # :nodoc:
129
+ class Callback # :nodoc:
130
+ def initialize(event, callback)
131
+ @event = event
132
+ @callback = callback
133
+ end
134
+
135
+ def before_commit
136
+ @callback.call if @event == :before_commit
137
+ end
138
+
139
+ def after_commit
140
+ @callback.call if @event == :after_commit
141
+ end
77
142
 
78
- def initialize(connection, options, run_commit_callbacks: false)
143
+ def after_rollback
144
+ @callback.call if @event == :after_rollback
145
+ end
146
+ end
147
+
148
+ attr_reader :connection, :state, :savepoint_name, :isolation_level, :user_transaction
149
+ attr_accessor :written
150
+
151
+ delegate :invalidate!, :invalidated?, to: :@state
152
+
153
+ def initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false)
154
+ super()
79
155
  @connection = connection
80
156
  @state = TransactionState.new
81
- @records = []
82
- @isolation_level = options[:isolation]
157
+ @callbacks = nil
158
+ @records = nil
159
+ @isolation_level = isolation
83
160
  @materialized = false
84
- @joinable = options.fetch(:joinable, true)
161
+ @joinable = joinable
85
162
  @run_commit_callbacks = run_commit_callbacks
163
+ @lazy_enrollment_records = nil
164
+ @dirty = false
165
+ @user_transaction = joinable ? ActiveRecord::Transaction.new(self) : ActiveRecord::Transaction::NULL_TRANSACTION
166
+ @instrumenter = TransactionInstrumenter.new(connection: connection, transaction: @user_transaction)
167
+ end
168
+
169
+ def dirty!
170
+ @dirty = true
171
+ end
172
+
173
+ def dirty?
174
+ @dirty
175
+ end
176
+
177
+ def open?
178
+ true
179
+ end
180
+
181
+ def closed?
182
+ false
183
+ end
184
+
185
+ def add_record(record, ensure_finalize = true)
186
+ @records ||= []
187
+ if ensure_finalize
188
+ @records << record
189
+ else
190
+ @lazy_enrollment_records ||= ObjectSpace::WeakMap.new
191
+ @lazy_enrollment_records[record] = record
192
+ end
86
193
  end
87
194
 
88
- def add_record(record)
89
- records << record
195
+ def before_commit(&block)
196
+ if @state.finalized?
197
+ raise ActiveRecordError, "Cannot register callbacks on a finalized transaction"
198
+ end
199
+
200
+ (@callbacks ||= []) << Callback.new(:before_commit, block)
201
+ end
202
+
203
+ def after_commit(&block)
204
+ if @state.finalized?
205
+ raise ActiveRecordError, "Cannot register callbacks on a finalized transaction"
206
+ end
207
+
208
+ (@callbacks ||= []) << Callback.new(:after_commit, block)
209
+ end
210
+
211
+ def after_rollback(&block)
212
+ if @state.finalized?
213
+ raise ActiveRecordError, "Cannot register callbacks on a finalized transaction"
214
+ end
215
+
216
+ (@callbacks ||= []) << Callback.new(:after_rollback, block)
217
+ end
218
+
219
+ def records
220
+ if @lazy_enrollment_records
221
+ @records.concat @lazy_enrollment_records.values
222
+ @lazy_enrollment_records = nil
223
+ end
224
+ @records
225
+ end
226
+
227
+ # Can this transaction's current state be recreated by
228
+ # rollback+begin ?
229
+ def restartable?
230
+ joinable? && !dirty?
231
+ end
232
+
233
+ def incomplete!
234
+ @instrumenter.finish(:incomplete) if materialized?
90
235
  end
91
236
 
92
237
  def materialize!
93
238
  @materialized = true
239
+ @instrumenter.start
94
240
  end
95
241
 
96
242
  def materialized?
97
243
  @materialized
98
244
  end
99
245
 
100
- def rollback_records
101
- ite = records.uniq(&:object_id)
102
- already_run_callbacks = {}
103
- while record = ite.shift
104
- trigger_callbacks = record.trigger_transactional_callbacks?
105
- should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
106
- already_run_callbacks[record] ||= trigger_callbacks
107
- record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks)
246
+ def restore!
247
+ if materialized?
248
+ incomplete!
249
+ @materialized = false
250
+ materialize!
108
251
  end
109
- ensure
110
- ite.each do |i|
111
- i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
252
+ end
253
+
254
+ def rollback_records
255
+ if records
256
+ begin
257
+ ite = unique_records
258
+
259
+ instances_to_run_callbacks_on = prepare_instances_to_run_callbacks_on(ite)
260
+
261
+ run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks|
262
+ record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks)
263
+ end
264
+ ensure
265
+ ite&.each do |i|
266
+ i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
267
+ end
268
+ end
112
269
  end
270
+
271
+ @callbacks&.each(&:after_rollback)
113
272
  end
114
273
 
115
274
  def before_commit_records
116
- records.uniq.each(&:before_committed!) if @run_commit_callbacks
275
+ if @run_commit_callbacks
276
+ if records
277
+ if ActiveRecord.before_committed_on_all_records
278
+ ite = unique_records
279
+
280
+ instances_to_run_callbacks_on = records.each_with_object({}) do |record, candidates|
281
+ candidates[record] = record
282
+ end
283
+
284
+ run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks|
285
+ record.before_committed! if should_run_callbacks
286
+ end
287
+ else
288
+ records.uniq.each(&:before_committed!)
289
+ end
290
+ end
291
+
292
+ @callbacks&.each(&:before_commit)
293
+ end
294
+ # Note: When @run_commit_callbacks is false #commit_records takes care of appending
295
+ # remaining callbacks to the parent transaction
117
296
  end
118
297
 
119
298
  def commit_records
120
- ite = records.uniq(&:object_id)
121
- already_run_callbacks = {}
122
- while record = ite.shift
123
- if @run_commit_callbacks
124
- trigger_callbacks = record.trigger_transactional_callbacks?
125
- should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
126
- already_run_callbacks[record] ||= trigger_callbacks
127
- record.committed!(should_run_callbacks: should_run_callbacks)
128
- else
129
- # if not running callbacks, only adds the record to the parent transaction
130
- connection.add_transaction_record(record)
299
+ if records
300
+ begin
301
+ ite = unique_records
302
+
303
+ if @run_commit_callbacks
304
+ instances_to_run_callbacks_on = prepare_instances_to_run_callbacks_on(ite)
305
+
306
+ run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks|
307
+ record.committed!(should_run_callbacks: should_run_callbacks)
308
+ end
309
+ else
310
+ while record = ite.shift
311
+ # if not running callbacks, only adds the record to the parent transaction
312
+ connection.add_transaction_record(record)
313
+ end
314
+ end
315
+ ensure
316
+ ite&.each { |i| i.committed!(should_run_callbacks: false) }
131
317
  end
132
318
  end
133
- ensure
134
- ite.each { |i| i.committed!(should_run_callbacks: false) }
319
+
320
+ if @run_commit_callbacks
321
+ @callbacks&.each(&:after_commit)
322
+ elsif @callbacks
323
+ connection.current_transaction.append_callbacks(@callbacks)
324
+ end
135
325
  end
136
326
 
137
327
  def full_rollback?; true; end
138
328
  def joinable?; @joinable; end
139
- def closed?; false; end
140
- def open?; !closed?; end
329
+
330
+ protected
331
+ def append_callbacks(callbacks) # :nodoc:
332
+ (@callbacks ||= []).concat(callbacks)
333
+ end
334
+
335
+ private
336
+ def unique_records
337
+ records.uniq(&:__id__)
338
+ end
339
+
340
+ def run_action_on_records(records, instances_to_run_callbacks_on)
341
+ while record = records.shift
342
+ should_run_callbacks = record.__id__ == instances_to_run_callbacks_on[record].__id__
343
+
344
+ yield record, should_run_callbacks
345
+ end
346
+ end
347
+
348
+ def prepare_instances_to_run_callbacks_on(records)
349
+ records.each_with_object({}) do |record, candidates|
350
+ next unless record.trigger_transactional_callbacks?
351
+
352
+ earlier_saved_candidate = candidates[record]
353
+
354
+ next if earlier_saved_candidate && record.class.run_commit_callbacks_on_first_saved_instances_in_transaction
355
+
356
+ # If the candidate instance destroyed itself in the database, then
357
+ # instances which were added to the transaction afterwards, and which
358
+ # think they updated themselves, are wrong. They should not replace
359
+ # our candidate as an instance to run callbacks on
360
+ next if earlier_saved_candidate&.destroyed? && !record.destroyed?
361
+
362
+ # If the candidate instance was created inside of this transaction,
363
+ # then instances which were subsequently loaded from the database
364
+ # and updated need that state transferred to them so that
365
+ # the after_create_commit callbacks are run
366
+ record._new_record_before_last_commit = true if earlier_saved_candidate&._new_record_before_last_commit
367
+
368
+ # The last instance to save itself is likeliest to have internal
369
+ # state that matches what's committed to the database
370
+ candidates[record] = record
371
+ end
372
+ end
373
+ end
374
+
375
+ # = Active Record Restart Parent \Transaction
376
+ class RestartParentTransaction < Transaction
377
+ def initialize(connection, parent_transaction, **options)
378
+ super(connection, **options)
379
+
380
+ @parent = parent_transaction
381
+
382
+ if isolation_level
383
+ raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
384
+ end
385
+
386
+ @parent.state.add_child(@state)
387
+ end
388
+
389
+ delegate :materialize!, :materialized?, :restart, to: :@parent
390
+
391
+ def rollback
392
+ @state.rollback!
393
+ @parent.restart
394
+ end
395
+
396
+ def commit
397
+ @state.commit!
398
+ end
399
+
400
+ def full_rollback?; false; end
141
401
  end
142
402
 
403
+ # = Active Record Savepoint \Transaction
143
404
  class SavepointTransaction < Transaction
144
- def initialize(connection, savepoint_name, parent_transaction, *args)
145
- super(connection, *args)
405
+ def initialize(connection, savepoint_name, parent_transaction, **options)
406
+ super(connection, **options)
146
407
 
147
408
  parent_transaction.state.add_child(@state)
148
409
 
@@ -158,19 +419,33 @@ module ActiveRecord
158
419
  super
159
420
  end
160
421
 
422
+ def restart
423
+ return unless materialized?
424
+
425
+ @instrumenter.finish(:restart)
426
+ @instrumenter.start
427
+
428
+ connection.rollback_to_savepoint(savepoint_name)
429
+ end
430
+
161
431
  def rollback
162
- connection.rollback_to_savepoint(savepoint_name) if materialized?
432
+ unless @state.invalidated?
433
+ connection.rollback_to_savepoint(savepoint_name) if materialized? && connection.active?
434
+ end
163
435
  @state.rollback!
436
+ @instrumenter.finish(:rollback) if materialized?
164
437
  end
165
438
 
166
439
  def commit
167
440
  connection.release_savepoint(savepoint_name) if materialized?
168
441
  @state.commit!
442
+ @instrumenter.finish(:commit) if materialized?
169
443
  end
170
444
 
171
445
  def full_rollback?; false; end
172
446
  end
173
447
 
448
+ # = Active Record Real \Transaction
174
449
  class RealTransaction < Transaction
175
450
  def materialize!
176
451
  if isolation_level
@@ -182,18 +457,34 @@ module ActiveRecord
182
457
  super
183
458
  end
184
459
 
460
+ def restart
461
+ return unless materialized?
462
+
463
+ @instrumenter.finish(:restart)
464
+
465
+ if connection.supports_restart_db_transaction?
466
+ @instrumenter.start
467
+ connection.restart_db_transaction
468
+ else
469
+ connection.rollback_db_transaction
470
+ materialize!
471
+ end
472
+ end
473
+
185
474
  def rollback
186
475
  connection.rollback_db_transaction if materialized?
187
476
  @state.full_rollback!
477
+ @instrumenter.finish(:rollback) if materialized?
188
478
  end
189
479
 
190
480
  def commit
191
481
  connection.commit_db_transaction if materialized?
192
482
  @state.full_commit!
483
+ @instrumenter.finish(:commit) if materialized?
193
484
  end
194
485
  end
195
486
 
196
- class TransactionManager #:nodoc:
487
+ class TransactionManager # :nodoc:
197
488
  def initialize(connection)
198
489
  @stack = []
199
490
  @connection = connection
@@ -202,21 +493,42 @@ module ActiveRecord
202
493
  @lazy_transactions_enabled = true
203
494
  end
204
495
 
205
- def begin_transaction(options = {})
496
+ def begin_transaction(isolation: nil, joinable: true, _lazy: true)
206
497
  @connection.lock.synchronize do
207
498
  run_commit_callbacks = !current_transaction.joinable?
208
499
  transaction =
209
500
  if @stack.empty?
210
- RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks)
501
+ RealTransaction.new(
502
+ @connection,
503
+ isolation: isolation,
504
+ joinable: joinable,
505
+ run_commit_callbacks: run_commit_callbacks
506
+ )
507
+ elsif current_transaction.restartable?
508
+ RestartParentTransaction.new(
509
+ @connection,
510
+ current_transaction,
511
+ isolation: isolation,
512
+ joinable: joinable,
513
+ run_commit_callbacks: run_commit_callbacks
514
+ )
211
515
  else
212
- SavepointTransaction.new(@connection, "active_record_#{@stack.size}", @stack.last, options,
213
- run_commit_callbacks: run_commit_callbacks)
516
+ SavepointTransaction.new(
517
+ @connection,
518
+ "active_record_#{@stack.size}",
519
+ current_transaction,
520
+ isolation: isolation,
521
+ joinable: joinable,
522
+ run_commit_callbacks: run_commit_callbacks
523
+ )
214
524
  end
215
525
 
216
- if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && options[:_lazy] != false
217
- @has_unmaterialized_transactions = true
218
- else
219
- transaction.materialize!
526
+ unless transaction.materialized?
527
+ if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && _lazy
528
+ @has_unmaterialized_transactions = true
529
+ else
530
+ transaction.materialize!
531
+ end
220
532
  end
221
533
  @stack.push(transaction)
222
534
  transaction
@@ -236,18 +548,35 @@ module ActiveRecord
236
548
  @lazy_transactions_enabled
237
549
  end
238
550
 
551
+ def dirty_current_transaction
552
+ current_transaction.dirty!
553
+ end
554
+
555
+ def restore_transactions
556
+ return false unless restorable?
557
+
558
+ @stack.each(&:restore!)
559
+
560
+ true
561
+ end
562
+
563
+ def restorable?
564
+ @stack.none?(&:dirty?)
565
+ end
566
+
239
567
  def materialize_transactions
240
568
  return if @materializing_transactions
241
- return unless @has_unmaterialized_transactions
242
569
 
243
- @connection.lock.synchronize do
244
- begin
245
- @materializing_transactions = true
246
- @stack.each { |t| t.materialize! unless t.materialized? }
247
- ensure
248
- @materializing_transactions = false
570
+ if @has_unmaterialized_transactions
571
+ @connection.lock.synchronize do
572
+ begin
573
+ @materializing_transactions = true
574
+ @stack.each { |t| t.materialize! unless t.materialized? }
575
+ ensure
576
+ @materializing_transactions = false
577
+ end
578
+ @has_unmaterialized_transactions = false
249
579
  end
250
- @has_unmaterialized_transactions = false
251
580
  end
252
581
  end
253
582
 
@@ -261,6 +590,8 @@ module ActiveRecord
261
590
  @stack.pop
262
591
  end
263
592
 
593
+ dirty_current_transaction if transaction.dirty?
594
+
264
595
  transaction.commit
265
596
  transaction.commit_records
266
597
  end
@@ -268,35 +599,48 @@ module ActiveRecord
268
599
 
269
600
  def rollback_transaction(transaction = nil)
270
601
  @connection.lock.synchronize do
271
- transaction ||= @stack.pop
272
- transaction.rollback
602
+ transaction ||= @stack.last
603
+ begin
604
+ transaction.rollback
605
+ ensure
606
+ @stack.pop if @stack.last == transaction
607
+ end
273
608
  transaction.rollback_records
274
609
  end
275
610
  end
276
611
 
277
- def within_new_transaction(options = {})
612
+ def within_new_transaction(isolation: nil, joinable: true)
278
613
  @connection.lock.synchronize do
279
- transaction = begin_transaction options
280
- yield
281
- rescue Exception => error
282
- if transaction
614
+ transaction = begin_transaction(isolation: isolation, joinable: joinable)
615
+ begin
616
+ yield transaction.user_transaction
617
+ rescue Exception => error
283
618
  rollback_transaction
284
619
  after_failure_actions(transaction, error)
285
- end
286
- raise
287
- ensure
288
- if !error && transaction
289
- if Thread.current.status == "aborting"
290
- rollback_transaction
291
- else
292
- begin
293
- commit_transaction
294
- rescue Exception
295
- rollback_transaction(transaction) unless transaction.state.completed?
296
- raise
620
+
621
+ raise
622
+ ensure
623
+ unless error
624
+ if Thread.current.status == "aborting"
625
+ rollback_transaction
626
+ else
627
+ begin
628
+ commit_transaction
629
+ rescue ActiveRecord::ConnectionFailed
630
+ transaction.invalidate! unless transaction.state.completed?
631
+ raise
632
+ rescue Exception
633
+ rollback_transaction(transaction) unless transaction.state.completed?
634
+ raise
635
+ end
297
636
  end
298
637
  end
299
638
  end
639
+ ensure
640
+ unless transaction&.state&.completed?
641
+ @connection.throw_away!
642
+ transaction&.incomplete!
643
+ end
300
644
  end
301
645
  end
302
646
 
@@ -309,8 +653,7 @@ module ActiveRecord
309
653
  end
310
654
 
311
655
  private
312
-
313
- NULL_TRANSACTION = NullTransaction.new
656
+ NULL_TRANSACTION = NullTransaction.new.freeze
314
657
 
315
658
  # Deallocate invalidated prepared statements outside of the transaction
316
659
  def after_failure_actions(transaction, error)