activerecord 6.1.7 → 7.2.0

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 (332) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +520 -1385
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +31 -31
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +17 -14
  7. data/lib/active_record/association_relation.rb +2 -12
  8. data/lib/active_record/associations/alias_tracker.rb +25 -19
  9. data/lib/active_record/associations/association.rb +60 -21
  10. data/lib/active_record/associations/association_scope.rb +17 -12
  11. data/lib/active_record/associations/belongs_to_association.rb +37 -11
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
  13. data/lib/active_record/associations/builder/association.rb +11 -5
  14. data/lib/active_record/associations/builder/belongs_to.rb +41 -14
  15. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +4 -4
  19. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  20. data/lib/active_record/associations/collection_association.rb +46 -36
  21. data/lib/active_record/associations/collection_proxy.rb +44 -16
  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 +10 -3
  25. data/lib/active_record/associations/has_many_association.rb +29 -19
  26. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  27. data/lib/active_record/associations/has_one_association.rb +20 -10
  28. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  29. data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
  30. data/lib/active_record/associations/join_dependency.rb +23 -15
  31. data/lib/active_record/associations/nested_error.rb +47 -0
  32. data/lib/active_record/associations/preloader/association.rb +212 -53
  33. data/lib/active_record/associations/preloader/batch.rb +48 -0
  34. data/lib/active_record/associations/preloader/branch.rb +153 -0
  35. data/lib/active_record/associations/preloader/through_association.rb +50 -16
  36. data/lib/active_record/associations/preloader.rb +50 -121
  37. data/lib/active_record/associations/singular_association.rb +15 -3
  38. data/lib/active_record/associations/through_association.rb +25 -14
  39. data/lib/active_record/associations.rb +404 -509
  40. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  41. data/lib/active_record/attribute_assignment.rb +2 -14
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  43. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  44. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  45. data/lib/active_record/attribute_methods/primary_key.rb +47 -27
  46. data/lib/active_record/attribute_methods/query.rb +31 -19
  47. data/lib/active_record/attribute_methods/read.rb +14 -11
  48. data/lib/active_record/attribute_methods/serialization.rb +174 -37
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -9
  50. data/lib/active_record/attribute_methods/write.rb +12 -15
  51. data/lib/active_record/attribute_methods.rb +164 -52
  52. data/lib/active_record/attributes.rb +51 -49
  53. data/lib/active_record/autosave_association.rb +74 -57
  54. data/lib/active_record/base.rb +27 -5
  55. data/lib/active_record/callbacks.rb +18 -34
  56. data/lib/active_record/coders/column_serializer.rb +61 -0
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +70 -46
  59. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +327 -612
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +201 -64
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +377 -142
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +345 -166
  75. data/lib/active_record/connection_adapters/column.rb +13 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -130
  78. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
  79. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  81. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  82. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
  83. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
  85. data/lib/active_record/connection_adapters/pool_config.rb +26 -16
  86. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  87. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  88. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +114 -54
  89. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  94. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  97. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  100. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
  103. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  104. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  105. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +173 -3
  106. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  107. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +401 -77
  108. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  109. data/lib/active_record/connection_adapters/postgresql_adapter.rb +518 -251
  110. data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
  111. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  112. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
  113. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
  114. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  115. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
  116. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +66 -22
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
  119. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  120. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  121. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  122. data/lib/active_record/connection_adapters.rb +130 -6
  123. data/lib/active_record/connection_handling.rb +132 -146
  124. data/lib/active_record/core.rb +276 -251
  125. data/lib/active_record/counter_cache.rb +68 -34
  126. data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -3
  127. data/lib/active_record/database_configurations/database_config.rb +34 -10
  128. data/lib/active_record/database_configurations/hash_config.rb +107 -31
  129. data/lib/active_record/database_configurations/url_config.rb +38 -13
  130. data/lib/active_record/database_configurations.rb +96 -60
  131. data/lib/active_record/delegated_type.rb +90 -20
  132. data/lib/active_record/deprecator.rb +7 -0
  133. data/lib/active_record/destroy_association_async_job.rb +4 -2
  134. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  135. data/lib/active_record/dynamic_matchers.rb +3 -3
  136. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  137. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  138. data/lib/active_record/encryption/cipher.rb +53 -0
  139. data/lib/active_record/encryption/config.rb +68 -0
  140. data/lib/active_record/encryption/configurable.rb +60 -0
  141. data/lib/active_record/encryption/context.rb +42 -0
  142. data/lib/active_record/encryption/contexts.rb +76 -0
  143. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  144. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  145. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  146. data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
  147. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  148. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  149. data/lib/active_record/encryption/encryptor.rb +170 -0
  150. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  151. data/lib/active_record/encryption/errors.rb +15 -0
  152. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  153. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  154. data/lib/active_record/encryption/key.rb +28 -0
  155. data/lib/active_record/encryption/key_generator.rb +53 -0
  156. data/lib/active_record/encryption/key_provider.rb +46 -0
  157. data/lib/active_record/encryption/message.rb +33 -0
  158. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  159. data/lib/active_record/encryption/message_serializer.rb +96 -0
  160. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  161. data/lib/active_record/encryption/properties.rb +76 -0
  162. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  163. data/lib/active_record/encryption/scheme.rb +100 -0
  164. data/lib/active_record/encryption.rb +56 -0
  165. data/lib/active_record/enum.rb +163 -63
  166. data/lib/active_record/errors.rb +210 -27
  167. data/lib/active_record/explain.rb +21 -12
  168. data/lib/active_record/explain_registry.rb +11 -6
  169. data/lib/active_record/explain_subscriber.rb +1 -1
  170. data/lib/active_record/fixture_set/file.rb +15 -1
  171. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  172. data/lib/active_record/fixture_set/render_context.rb +2 -0
  173. data/lib/active_record/fixture_set/table_row.rb +70 -14
  174. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  175. data/lib/active_record/fixtures.rb +179 -112
  176. data/lib/active_record/future_result.rb +178 -0
  177. data/lib/active_record/gem_version.rb +4 -4
  178. data/lib/active_record/inheritance.rb +85 -31
  179. data/lib/active_record/insert_all.rb +148 -32
  180. data/lib/active_record/integration.rb +14 -10
  181. data/lib/active_record/internal_metadata.rb +123 -23
  182. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  183. data/lib/active_record/locking/optimistic.rb +43 -27
  184. data/lib/active_record/locking/pessimistic.rb +15 -6
  185. data/lib/active_record/log_subscriber.rb +41 -29
  186. data/lib/active_record/marshalling.rb +56 -0
  187. data/lib/active_record/message_pack.rb +124 -0
  188. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  189. data/lib/active_record/middleware/database_selector.rb +23 -13
  190. data/lib/active_record/middleware/shard_selector.rb +62 -0
  191. data/lib/active_record/migration/command_recorder.rb +113 -16
  192. data/lib/active_record/migration/compatibility.rb +235 -46
  193. data/lib/active_record/migration/default_strategy.rb +22 -0
  194. data/lib/active_record/migration/execution_strategy.rb +19 -0
  195. data/lib/active_record/migration/join_table.rb +1 -1
  196. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  197. data/lib/active_record/migration.rb +374 -177
  198. data/lib/active_record/model_schema.rb +143 -159
  199. data/lib/active_record/nested_attributes.rb +48 -21
  200. data/lib/active_record/no_touching.rb +3 -3
  201. data/lib/active_record/normalization.rb +163 -0
  202. data/lib/active_record/persistence.rb +282 -283
  203. data/lib/active_record/promise.rb +84 -0
  204. data/lib/active_record/query_cache.rb +19 -25
  205. data/lib/active_record/query_logs.rb +189 -0
  206. data/lib/active_record/query_logs_formatter.rb +41 -0
  207. data/lib/active_record/querying.rb +44 -9
  208. data/lib/active_record/railtie.rb +234 -71
  209. data/lib/active_record/railties/controller_runtime.rb +25 -11
  210. data/lib/active_record/railties/databases.rake +189 -256
  211. data/lib/active_record/railties/job_runtime.rb +23 -0
  212. data/lib/active_record/readonly_attributes.rb +41 -3
  213. data/lib/active_record/reflection.rb +325 -103
  214. data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
  215. data/lib/active_record/relation/batches.rb +198 -63
  216. data/lib/active_record/relation/calculations.rb +300 -111
  217. data/lib/active_record/relation/delegation.rb +33 -22
  218. data/lib/active_record/relation/finder_methods.rb +123 -52
  219. data/lib/active_record/relation/merger.rb +26 -19
  220. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  221. data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
  222. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  223. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  224. data/lib/active_record/relation/predicate_builder.rb +29 -22
  225. data/lib/active_record/relation/query_attribute.rb +30 -12
  226. data/lib/active_record/relation/query_methods.rb +842 -150
  227. data/lib/active_record/relation/record_fetch_warning.rb +10 -9
  228. data/lib/active_record/relation/spawn_methods.rb +7 -6
  229. data/lib/active_record/relation/where_clause.rb +15 -36
  230. data/lib/active_record/relation.rb +736 -145
  231. data/lib/active_record/result.rb +67 -54
  232. data/lib/active_record/runtime_registry.rb +71 -13
  233. data/lib/active_record/sanitization.rb +84 -34
  234. data/lib/active_record/schema.rb +39 -23
  235. data/lib/active_record/schema_dumper.rb +90 -31
  236. data/lib/active_record/schema_migration.rb +74 -23
  237. data/lib/active_record/scoping/default.rb +72 -15
  238. data/lib/active_record/scoping/named.rb +5 -13
  239. data/lib/active_record/scoping.rb +65 -34
  240. data/lib/active_record/secure_password.rb +60 -0
  241. data/lib/active_record/secure_token.rb +21 -3
  242. data/lib/active_record/serialization.rb +6 -1
  243. data/lib/active_record/signed_id.rb +30 -9
  244. data/lib/active_record/statement_cache.rb +7 -7
  245. data/lib/active_record/store.rb +10 -10
  246. data/lib/active_record/suppressor.rb +13 -15
  247. data/lib/active_record/table_metadata.rb +7 -3
  248. data/lib/active_record/tasks/database_tasks.rb +277 -149
  249. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  250. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  251. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
  252. data/lib/active_record/test_databases.rb +1 -1
  253. data/lib/active_record/test_fixtures.rb +173 -155
  254. data/lib/active_record/testing/query_assertions.rb +121 -0
  255. data/lib/active_record/timestamp.rb +32 -19
  256. data/lib/active_record/token_for.rb +123 -0
  257. data/lib/active_record/touch_later.rb +12 -7
  258. data/lib/active_record/transaction.rb +132 -0
  259. data/lib/active_record/transactions.rb +118 -41
  260. data/lib/active_record/translation.rb +3 -5
  261. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  262. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  263. data/lib/active_record/type/internal/timezone.rb +7 -2
  264. data/lib/active_record/type/serialized.rb +9 -7
  265. data/lib/active_record/type/time.rb +4 -0
  266. data/lib/active_record/type/type_map.rb +17 -20
  267. data/lib/active_record/type.rb +1 -2
  268. data/lib/active_record/type_caster/connection.rb +4 -4
  269. data/lib/active_record/validations/absence.rb +1 -1
  270. data/lib/active_record/validations/associated.rb +13 -7
  271. data/lib/active_record/validations/numericality.rb +5 -4
  272. data/lib/active_record/validations/presence.rb +5 -28
  273. data/lib/active_record/validations/uniqueness.rb +64 -15
  274. data/lib/active_record/validations.rb +12 -5
  275. data/lib/active_record/version.rb +1 -1
  276. data/lib/active_record.rb +444 -32
  277. data/lib/arel/alias_predication.rb +1 -1
  278. data/lib/arel/attributes/attribute.rb +0 -8
  279. data/lib/arel/collectors/bind.rb +2 -0
  280. data/lib/arel/collectors/composite.rb +7 -0
  281. data/lib/arel/collectors/sql_string.rb +1 -1
  282. data/lib/arel/collectors/substitute_binds.rb +1 -1
  283. data/lib/arel/crud.rb +28 -22
  284. data/lib/arel/delete_manager.rb +18 -4
  285. data/lib/arel/errors.rb +10 -0
  286. data/lib/arel/factory_methods.rb +4 -0
  287. data/lib/arel/filter_predications.rb +9 -0
  288. data/lib/arel/insert_manager.rb +2 -3
  289. data/lib/arel/nodes/binary.rb +6 -7
  290. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  291. data/lib/arel/nodes/casted.rb +1 -1
  292. data/lib/arel/nodes/cte.rb +36 -0
  293. data/lib/arel/nodes/delete_statement.rb +12 -13
  294. data/lib/arel/nodes/filter.rb +10 -0
  295. data/lib/arel/nodes/fragments.rb +35 -0
  296. data/lib/arel/nodes/function.rb +1 -0
  297. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  298. data/lib/arel/nodes/insert_statement.rb +2 -2
  299. data/lib/arel/nodes/leading_join.rb +8 -0
  300. data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
  301. data/lib/arel/nodes/node.rb +115 -5
  302. data/lib/arel/nodes/select_core.rb +2 -2
  303. data/lib/arel/nodes/select_statement.rb +2 -2
  304. data/lib/arel/nodes/sql_literal.rb +13 -0
  305. data/lib/arel/nodes/table_alias.rb +4 -0
  306. data/lib/arel/nodes/update_statement.rb +8 -3
  307. data/lib/arel/nodes.rb +7 -2
  308. data/lib/arel/predications.rb +14 -4
  309. data/lib/arel/select_manager.rb +11 -5
  310. data/lib/arel/table.rb +9 -6
  311. data/lib/arel/tree_manager.rb +8 -15
  312. data/lib/arel/update_manager.rb +20 -5
  313. data/lib/arel/visitors/dot.rb +81 -90
  314. data/lib/arel/visitors/mysql.rb +23 -5
  315. data/lib/arel/visitors/postgresql.rb +1 -22
  316. data/lib/arel/visitors/to_sql.rb +170 -36
  317. data/lib/arel/visitors/visitor.rb +2 -2
  318. data/lib/arel.rb +23 -4
  319. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  320. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  321. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  322. data/lib/rails/generators/active_record/migration.rb +3 -1
  323. data/lib/rails/generators/active_record/model/USAGE +113 -0
  324. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  325. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  326. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  327. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  328. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  329. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  330. metadata +100 -14
  331. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  332. data/lib/active_record/null_relation.rb +0 -67
@@ -7,33 +7,21 @@ module ActiveRecord
7
7
  64
8
8
  end
9
9
 
10
- # Returns the maximum length of a table alias.
11
- def table_alias_length
10
+ # Returns the maximum length of a table name.
11
+ def table_name_length
12
12
  max_identifier_length
13
13
  end
14
14
 
15
- # Returns the maximum allowed length for an index name. This
16
- # limit is enforced by \Rails and is less than or equal to
17
- # #index_name_length. The gap between
18
- # #index_name_length is to allow internal \Rails
19
- # operations to use prefixes in temporary operations.
20
- def allowed_index_name_length
21
- index_name_length
15
+ # Returns the maximum length of a table alias.
16
+ def table_alias_length
17
+ max_identifier_length
22
18
  end
23
- deprecate :allowed_index_name_length
24
19
 
25
20
  # Returns the maximum length of an index name.
26
21
  def index_name_length
27
22
  max_identifier_length
28
23
  end
29
24
 
30
- # Returns the maximum number of elements in an IN (x,y,z) clause.
31
- # +nil+ means no limit.
32
- def in_clause_length
33
- nil
34
- end
35
- deprecate :in_clause_length
36
-
37
25
  private
38
26
  def bind_params_length
39
27
  65535
@@ -14,18 +14,24 @@ module ActiveRecord
14
14
  sql
15
15
  end
16
16
 
17
- def to_sql_and_binds(arel_or_sql_string, binds = [], preparable = nil) # :nodoc:
17
+ def to_sql_and_binds(arel_or_sql_string, binds = [], preparable = nil, allow_retry = false) # :nodoc:
18
+ # Arel::TreeManager -> Arel::Node
18
19
  if arel_or_sql_string.respond_to?(:ast)
20
+ arel_or_sql_string = arel_or_sql_string.ast
21
+ end
22
+
23
+ if Arel.arel_node?(arel_or_sql_string) && !(String === arel_or_sql_string)
19
24
  unless binds.empty?
20
25
  raise "Passing bind parameters with an arel AST is forbidden. " \
21
26
  "The values must be stored on the AST directly"
22
27
  end
23
28
 
24
29
  collector = collector()
30
+ collector.retryable = true
25
31
 
26
32
  if prepared_statements
27
33
  collector.preparable = true
28
- sql, binds = visitor.compile(arel_or_sql_string.ast, collector)
34
+ sql, binds = visitor.compile(arel_or_sql_string, collector)
29
35
 
30
36
  if binds.length > bind_params_length
31
37
  unprepared_statement do
@@ -34,12 +40,13 @@ module ActiveRecord
34
40
  end
35
41
  preparable = collector.preparable
36
42
  else
37
- sql = visitor.compile(arel_or_sql_string.ast, collector)
43
+ sql = visitor.compile(arel_or_sql_string, collector)
38
44
  end
39
- [sql.freeze, binds, preparable]
45
+ allow_retry = collector.retryable
46
+ [sql.freeze, binds, preparable, allow_retry]
40
47
  else
41
48
  arel_or_sql_string = arel_or_sql_string.dup.freeze unless arel_or_sql_string.frozen?
42
- [arel_or_sql_string, binds, preparable]
49
+ [arel_or_sql_string, binds, preparable, allow_retry]
43
50
  end
44
51
  end
45
52
  private :to_sql_and_binds
@@ -59,28 +66,28 @@ module ActiveRecord
59
66
  end
60
67
 
61
68
  # Returns an ActiveRecord::Result instance.
62
- def select_all(arel, name = nil, binds = [], preparable: nil)
69
+ def select_all(arel, name = nil, binds = [], preparable: nil, async: false, allow_retry: false)
63
70
  arel = arel_from_relation(arel)
64
- sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
71
+ sql, binds, preparable, allow_retry = to_sql_and_binds(arel, binds, preparable, allow_retry)
65
72
 
66
- if prepared_statements && preparable
67
- select_prepared(sql, name, binds)
68
- else
69
- select(sql, name, binds)
70
- end
73
+ select(sql, name, binds,
74
+ prepare: prepared_statements && preparable,
75
+ async: async && FutureResult::SelectAll,
76
+ allow_retry: allow_retry
77
+ )
71
78
  rescue ::RangeError
72
- ActiveRecord::Result.new([], [])
79
+ ActiveRecord::Result.empty(async: async)
73
80
  end
74
81
 
75
82
  # Returns a record hash with the column names as keys and column values
76
83
  # as values.
77
- def select_one(arel, name = nil, binds = [])
78
- select_all(arel, name, binds).first
84
+ def select_one(arel, name = nil, binds = [], async: false)
85
+ select_all(arel, name, binds, async: async).then(&:first)
79
86
  end
80
87
 
81
88
  # Returns a single value from a record
82
- def select_value(arel, name = nil, binds = [])
83
- single_value_from_rows(select_rows(arel, name, binds))
89
+ def select_value(arel, name = nil, binds = [], async: false)
90
+ select_rows(arel, name, binds, async: async).then { |rows| single_value_from_rows(rows) }
84
91
  end
85
92
 
86
93
  # Returns an array of the values of the first column in a select:
@@ -91,8 +98,8 @@ module ActiveRecord
91
98
 
92
99
  # Returns an array of arrays containing the field values.
93
100
  # Order is the same as that returned by +columns+.
94
- def select_rows(arel, name = nil, binds = [])
95
- select_all(arel, name, binds).rows
101
+ def select_rows(arel, name = nil, binds = [], async: false)
102
+ select_all(arel, name, binds, async: async).then(&:rows)
96
103
  end
97
104
 
98
105
  def query_value(sql, name = nil) # :nodoc:
@@ -104,7 +111,7 @@ module ActiveRecord
104
111
  end
105
112
 
106
113
  def query(sql, name = nil) # :nodoc:
107
- exec_query(sql, name).rows
114
+ internal_exec_query(sql, name).rows
108
115
  end
109
116
 
110
117
  # Determines whether the SQL statement is a write query.
@@ -114,47 +121,63 @@ module ActiveRecord
114
121
 
115
122
  # Executes the SQL statement in the context of this connection and returns
116
123
  # the raw result from the connection adapter.
124
+ #
125
+ # Setting +allow_retry+ to true causes the db to reconnect and retry
126
+ # executing the SQL statement in case of a connection-related exception.
127
+ # This option should only be enabled for known idempotent queries.
128
+ #
129
+ # Note: the query is assumed to have side effects and the query cache
130
+ # will be cleared. If the query is read-only, consider using #select_all
131
+ # instead.
132
+ #
117
133
  # Note: depending on your database connector, the result returned by this
118
- # method may be manually memory managed. Consider using the exec_query
134
+ # method may be manually memory managed. Consider using #exec_query
119
135
  # wrapper instead.
120
- def execute(sql, name = nil)
121
- raise NotImplementedError
136
+ def execute(sql, name = nil, allow_retry: false)
137
+ internal_execute(sql, name, allow_retry: allow_retry)
122
138
  end
123
139
 
124
140
  # Executes +sql+ statement in the context of this connection using
125
141
  # +binds+ as the bind substitutes. +name+ is logged along with
126
142
  # the executed +sql+ statement.
143
+ #
144
+ # Note: the query is assumed to have side effects and the query cache
145
+ # will be cleared. If the query is read-only, consider using #select_all
146
+ # instead.
127
147
  def exec_query(sql, name = "SQL", binds = [], prepare: false)
128
- raise NotImplementedError
148
+ internal_exec_query(sql, name, binds, prepare: prepare)
129
149
  end
130
150
 
131
151
  # Executes insert +sql+ statement in the context of this connection using
132
152
  # +binds+ as the bind substitutes. +name+ is logged along with
133
153
  # the executed +sql+ statement.
134
- def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
135
- sql, binds = sql_for_insert(sql, pk, binds)
136
- exec_query(sql, name, binds)
154
+ # Some adapters support the `returning` keyword argument which allows to control the result of the query:
155
+ # `nil` is the default value and maintains default behavior. If an array of column names is passed -
156
+ # the result will contain values of the specified columns from the inserted row.
157
+ def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil)
158
+ sql, binds = sql_for_insert(sql, pk, binds, returning)
159
+ internal_exec_query(sql, name, binds)
137
160
  end
138
161
 
139
162
  # Executes delete +sql+ statement in the context of this connection using
140
163
  # +binds+ as the bind substitutes. +name+ is logged along with
141
164
  # the executed +sql+ statement.
142
165
  def exec_delete(sql, name = nil, binds = [])
143
- exec_query(sql, name, binds)
166
+ internal_exec_query(sql, name, binds)
144
167
  end
145
168
 
146
169
  # Executes update +sql+ statement in the context of this connection using
147
170
  # +binds+ as the bind substitutes. +name+ is logged along with
148
171
  # the executed +sql+ statement.
149
172
  def exec_update(sql, name = nil, binds = [])
150
- exec_query(sql, name, binds)
173
+ internal_exec_query(sql, name, binds)
151
174
  end
152
175
 
153
176
  def exec_insert_all(sql, name) # :nodoc:
154
- exec_query(sql, name)
177
+ internal_exec_query(sql, name)
155
178
  end
156
179
 
157
- def explain(arel, binds = []) # :nodoc:
180
+ def explain(arel, binds = [], options = []) # :nodoc:
158
181
  raise NotImplementedError
159
182
  end
160
183
 
@@ -166,9 +189,15 @@ module ActiveRecord
166
189
  #
167
190
  # If the next id was calculated in advance (as in Oracle), it should be
168
191
  # passed in as +id_value+.
169
- def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
192
+ # Some adapters support the `returning` keyword argument which allows defining the return value of the method:
193
+ # `nil` is the default value and maintains default behavior. If an array of column names is passed -
194
+ # an array of is returned from the method representing values of the specified columns from the inserted row.
195
+ def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil)
170
196
  sql, binds = to_sql_and_binds(arel, binds)
171
- value = exec_insert(sql, name, binds, pk, sequence_name)
197
+ value = exec_insert(sql, name, binds, pk, sequence_name, returning: returning)
198
+
199
+ return returning_column_values(value) unless returning.nil?
200
+
172
201
  id_value || last_inserted_id(value)
173
202
  end
174
203
  alias create insert
@@ -191,7 +220,7 @@ module ActiveRecord
191
220
  end
192
221
 
193
222
  def truncate_tables(*table_names) # :nodoc:
194
- table_names -= [schema_migration.table_name, InternalMetadata.table_name]
223
+ table_names -= [pool.schema_migration.table_name, pool.internal_metadata.table_name]
195
224
 
196
225
  return if table_names.empty?
197
226
 
@@ -206,6 +235,17 @@ module ActiveRecord
206
235
  # Runs the given block in a database transaction, and returns the result
207
236
  # of the block.
208
237
  #
238
+ # == Transaction callbacks
239
+ #
240
+ # #transaction yields an ActiveRecord::Transaction object on which it is
241
+ # possible to register callback:
242
+ #
243
+ # ActiveRecord::Base.transaction do |transaction|
244
+ # transaction.before_commit { puts "before commit!" }
245
+ # transaction.after_commit { puts "after commit!" }
246
+ # transaction.after_rollback { puts "after rollback!" }
247
+ # end
248
+ #
209
249
  # == Nested transactions support
210
250
  #
211
251
  # #transaction calls can be nested. By default, this makes all database
@@ -273,9 +313,9 @@ module ActiveRecord
273
313
  # #transaction will raise exceptions when it tries to release the
274
314
  # already-automatically-released savepoints:
275
315
  #
276
- # Model.connection.transaction do # BEGIN
277
- # Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
278
- # Model.connection.create_table(...)
316
+ # Model.lease_connection.transaction do # BEGIN
317
+ # Model.lease_connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
318
+ # Model.lease_connection.create_table(...)
279
319
  # # active_record_1 now automatically released
280
320
  # end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
281
321
  # end
@@ -308,26 +348,28 @@ module ActiveRecord
308
348
  # * You are joining an existing open transaction
309
349
  # * You are creating a nested (savepoint) transaction
310
350
  #
311
- # The mysql2 and postgresql adapters support setting the transaction
351
+ # The mysql2, trilogy, and postgresql adapters support setting the transaction
312
352
  # isolation level.
313
- def transaction(requires_new: nil, isolation: nil, joinable: true)
353
+ # :args: (requires_new: nil, isolation: nil, &block)
354
+ def transaction(requires_new: nil, isolation: nil, joinable: true, &block)
314
355
  if !requires_new && current_transaction.joinable?
315
356
  if isolation
316
357
  raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
317
358
  end
318
- yield
359
+ yield current_transaction.user_transaction
319
360
  else
320
- transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable) { yield }
361
+ transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable, &block)
321
362
  end
322
363
  rescue ActiveRecord::Rollback
323
364
  # rollbacks are silently swallowed
324
365
  end
325
366
 
326
- attr_reader :transaction_manager #:nodoc:
367
+ attr_reader :transaction_manager # :nodoc:
327
368
 
328
369
  delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
329
370
  :commit_transaction, :rollback_transaction, :materialize_transactions,
330
- :disable_lazy_transactions!, :enable_lazy_transactions!, to: :transaction_manager
371
+ :disable_lazy_transactions!, :enable_lazy_transactions!, :dirty_current_transaction,
372
+ to: :transaction_manager
331
373
 
332
374
  def mark_transaction_written_if_write(sql) # :nodoc:
333
375
  transaction = current_transaction
@@ -340,8 +382,24 @@ module ActiveRecord
340
382
  current_transaction.open?
341
383
  end
342
384
 
343
- def reset_transaction #:nodoc:
385
+ def reset_transaction(restore: false) # :nodoc:
386
+ # Store the existing transaction state to the side
387
+ old_state = @transaction_manager if restore && @transaction_manager&.restorable?
388
+
344
389
  @transaction_manager = ConnectionAdapters::TransactionManager.new(self)
390
+
391
+ if block_given?
392
+ # Reconfigure the connection without any transaction state in the way
393
+ result = yield
394
+
395
+ # Now the connection's fully established, we can swap back
396
+ if old_state
397
+ @transaction_manager = old_state
398
+ @transaction_manager.restore_transactions
399
+ end
400
+
401
+ result
402
+ end
345
403
  end
346
404
 
347
405
  # Register a record with the current transaction so that its after_commit and after_rollback callbacks
@@ -376,9 +434,17 @@ module ActiveRecord
376
434
  # done if the transaction block raises an exception or returns false.
377
435
  def rollback_db_transaction
378
436
  exec_rollback_db_transaction
437
+ rescue ActiveRecord::ConnectionNotEstablished, ActiveRecord::ConnectionFailed
438
+ # Connection's gone; that counts as a rollback
439
+ end
440
+
441
+ def exec_rollback_db_transaction() end # :nodoc:
442
+
443
+ def restart_db_transaction
444
+ exec_restart_db_transaction
379
445
  end
380
446
 
381
- def exec_rollback_db_transaction() end #:nodoc:
447
+ def exec_restart_db_transaction() end # :nodoc:
382
448
 
383
449
  def rollback_to_savepoint(name = nil)
384
450
  exec_rollback_to_savepoint(name)
@@ -397,7 +463,7 @@ module ActiveRecord
397
463
  # something beyond a simple insert (e.g. Oracle).
398
464
  # Most of adapters should implement +insert_fixtures_set+ that leverages bulk SQL insert.
399
465
  # We keep this method to provide fallback
400
- # for databases like sqlite that do not support bulk inserts.
466
+ # for databases like SQLite that do not support bulk inserts.
401
467
  def insert_fixture(fixture, table_name)
402
468
  execute(build_fixture_sql(Array.wrap(fixture), table_name), "Fixture Insert")
403
469
  end
@@ -408,8 +474,8 @@ module ActiveRecord
408
474
  statements = table_deletes + fixture_inserts
409
475
 
410
476
  with_multi_statements do
411
- disable_referential_integrity do
412
- transaction(requires_new: true) do
477
+ transaction(requires_new: true) do
478
+ disable_referential_integrity do
413
479
  execute_batch(statements, "Fixtures Load")
414
480
  end
415
481
  end
@@ -445,13 +511,43 @@ module ActiveRecord
445
511
  end
446
512
  end
447
513
 
514
+ # This is a safe default, even if not high precision on all databases
515
+ HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP", retryable: true).freeze # :nodoc:
516
+ private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
517
+
518
+ # Returns an Arel SQL literal for the CURRENT_TIMESTAMP for usage with
519
+ # arbitrary precision date/time columns.
520
+ #
521
+ # Adapters supporting datetime with precision should override this to
522
+ # provide as much precision as is available.
523
+ def high_precision_current_timestamp
524
+ HIGH_PRECISION_CURRENT_TIMESTAMP
525
+ end
526
+
527
+ def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false) # :nodoc:
528
+ raise NotImplementedError
529
+ end
530
+
448
531
  private
532
+ def internal_execute(sql, name = "SCHEMA", allow_retry: false, materialize_transactions: true)
533
+ sql = transform_query(sql)
534
+ check_if_write_query(sql)
535
+
536
+ mark_transaction_written_if_write(sql)
537
+
538
+ raw_execute(sql, name, allow_retry: allow_retry, materialize_transactions: materialize_transactions)
539
+ end
540
+
449
541
  def execute_batch(statements, name = nil)
450
542
  statements.each do |statement|
451
- execute(statement, name)
543
+ internal_execute(statement, name)
452
544
  end
453
545
  end
454
546
 
547
+ def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
548
+ raise NotImplementedError
549
+ end
550
+
455
551
  DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
456
552
  private_constant :DEFAULT_INSERT_VALUE
457
553
 
@@ -460,7 +556,7 @@ module ActiveRecord
460
556
  end
461
557
 
462
558
  def build_fixture_sql(fixtures, table_name)
463
- columns = schema_cache.columns_hash(table_name)
559
+ columns = schema_cache.columns_hash(table_name).reject { |_, column| supports_virtual_columns? && column.virtual? }
464
560
 
465
561
  values_list = fixtures.map do |fixture|
466
562
  fixture = fixture.stringify_keys
@@ -481,8 +577,7 @@ module ActiveRecord
481
577
  end
482
578
 
483
579
  table = Arel::Table.new(table_name)
484
- manager = Arel::InsertManager.new
485
- manager.into(table)
580
+ manager = Arel::InsertManager.new(table)
486
581
 
487
582
  if values_list.size == 1
488
583
  values = values_list.shift
@@ -503,10 +598,10 @@ module ActiveRecord
503
598
  end
504
599
 
505
600
  def build_fixture_statements(fixture_set)
506
- fixture_set.map do |table_name, fixtures|
601
+ fixture_set.filter_map do |table_name, fixtures|
507
602
  next if fixtures.empty?
508
603
  build_fixture_sql(fixtures, table_name)
509
- end.compact
604
+ end
510
605
  end
511
606
 
512
607
  def build_truncate_statement(table_name)
@@ -528,15 +623,49 @@ module ActiveRecord
528
623
  end
529
624
 
530
625
  # Returns an ActiveRecord::Result instance.
531
- def select(sql, name = nil, binds = [])
532
- exec_query(sql, name, binds, prepare: false)
533
- end
626
+ def select(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false)
627
+ if async && async_enabled?
628
+ if current_transaction.joinable?
629
+ raise AsynchronousQueryInsideTransactionError, "Asynchronous queries are not allowed inside transactions"
630
+ end
534
631
 
535
- def select_prepared(sql, name = nil, binds = [])
536
- exec_query(sql, name, binds, prepare: true)
632
+ future_result = async.new(
633
+ pool,
634
+ sql,
635
+ name,
636
+ binds,
637
+ prepare: prepare,
638
+ )
639
+ if supports_concurrent_connections? && current_transaction.closed?
640
+ future_result.schedule!(ActiveRecord::Base.asynchronous_queries_session)
641
+ else
642
+ future_result.execute!(self)
643
+ end
644
+ return future_result
645
+ end
646
+
647
+ result = internal_exec_query(sql, name, binds, prepare: prepare, allow_retry: allow_retry)
648
+ if async
649
+ FutureResult.wrap(result)
650
+ else
651
+ result
652
+ end
537
653
  end
538
654
 
539
- def sql_for_insert(sql, pk, binds)
655
+ def sql_for_insert(sql, pk, binds, returning) # :nodoc:
656
+ if supports_insert_returning?
657
+ if pk.nil?
658
+ # Extract the table from the insert sql. Yuck.
659
+ table_ref = extract_table_ref_from_insert_sql(sql)
660
+ pk = primary_key(table_ref) if table_ref
661
+ end
662
+
663
+ returning_columns = returning || Array(pk)
664
+
665
+ returning_columns_statement = returning_columns.map { |c| quote_column_name(c) }.join(", ")
666
+ sql = "#{sql} RETURNING #{returning_columns_statement}" if returning_columns.any?
667
+ end
668
+
540
669
  [sql, binds]
541
670
  end
542
671
 
@@ -544,6 +673,10 @@ module ActiveRecord
544
673
  single_value_from_rows(result.rows)
545
674
  end
546
675
 
676
+ def returning_column_values(result)
677
+ [last_inserted_id(result)]
678
+ end
679
+
547
680
  def single_value_from_rows(rows)
548
681
  row = rows.first
549
682
  row && row.first
@@ -556,6 +689,12 @@ module ActiveRecord
556
689
  relation
557
690
  end
558
691
  end
692
+
693
+ def extract_table_ref_from_insert_sql(sql)
694
+ if sql =~ /into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im
695
+ $1.delete('"').strip
696
+ end
697
+ end
559
698
  end
560
699
  end
561
700
  end