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
@@ -14,29 +14,39 @@ module ActiveRecord
14
14
  sql
15
15
  end
16
16
 
17
- def to_sql_and_binds(arel_or_sql_string, binds = []) # :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
 
29
+ collector = collector()
30
+ collector.retryable = true
31
+
24
32
  if prepared_statements
25
- sql, binds = visitor.compile(arel_or_sql_string.ast, collector)
33
+ collector.preparable = true
34
+ sql, binds = visitor.compile(arel_or_sql_string, collector)
26
35
 
27
36
  if binds.length > bind_params_length
28
37
  unprepared_statement do
29
- sql, binds = to_sql_and_binds(arel_or_sql_string)
30
- visitor.preparable = false
38
+ return to_sql_and_binds(arel_or_sql_string)
31
39
  end
32
40
  end
41
+ preparable = collector.preparable
33
42
  else
34
- sql = visitor.compile(arel_or_sql_string.ast, collector)
43
+ sql = visitor.compile(arel_or_sql_string, collector)
35
44
  end
36
- [sql.freeze, binds]
45
+ allow_retry = collector.retryable
46
+ [sql.freeze, binds, preparable, allow_retry]
37
47
  else
38
- visitor.preparable = false if prepared_statements
39
- [arel_or_sql_string.dup.freeze, binds]
48
+ arel_or_sql_string = arel_or_sql_string.dup.freeze unless arel_or_sql_string.frozen?
49
+ [arel_or_sql_string, binds, preparable, allow_retry]
40
50
  end
41
51
  end
42
52
  private :to_sql_and_binds
@@ -56,30 +66,28 @@ module ActiveRecord
56
66
  end
57
67
 
58
68
  # Returns an ActiveRecord::Result instance.
59
- def select_all(arel, name = nil, binds = [], preparable: nil)
69
+ def select_all(arel, name = nil, binds = [], preparable: nil, async: false, allow_retry: false)
60
70
  arel = arel_from_relation(arel)
61
- sql, binds = to_sql_and_binds(arel, binds)
62
-
63
- if preparable.nil?
64
- preparable = prepared_statements ? visitor.preparable : false
65
- end
71
+ sql, binds, preparable, allow_retry = to_sql_and_binds(arel, binds, preparable, allow_retry)
66
72
 
67
- if prepared_statements && preparable
68
- select_prepared(sql, name, binds)
69
- else
70
- select(sql, name, binds)
71
- end
73
+ select(sql, name, binds,
74
+ prepare: prepared_statements && preparable,
75
+ async: async && FutureResult::SelectAll,
76
+ allow_retry: allow_retry
77
+ )
78
+ rescue ::RangeError
79
+ ActiveRecord::Result.empty(async: async)
72
80
  end
73
81
 
74
82
  # Returns a record hash with the column names as keys and column values
75
83
  # as values.
76
- def select_one(arel, name = nil, binds = [])
77
- 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)
78
86
  end
79
87
 
80
88
  # Returns a single value from a record
81
- def select_value(arel, name = nil, binds = [])
82
- 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) }
83
91
  end
84
92
 
85
93
  # Returns an array of the values of the first column in a select:
@@ -90,8 +98,8 @@ module ActiveRecord
90
98
 
91
99
  # Returns an array of arrays containing the field values.
92
100
  # Order is the same as that returned by +columns+.
93
- def select_rows(arel, name = nil, binds = [])
94
- 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)
95
103
  end
96
104
 
97
105
  def query_value(sql, name = nil) # :nodoc:
@@ -103,7 +111,7 @@ module ActiveRecord
103
111
  end
104
112
 
105
113
  def query(sql, name = nil) # :nodoc:
106
- exec_query(sql, name).rows
114
+ internal_exec_query(sql, name).rows
107
115
  end
108
116
 
109
117
  # Determines whether the SQL statement is a write query.
@@ -113,40 +121,64 @@ module ActiveRecord
113
121
 
114
122
  # Executes the SQL statement in the context of this connection and returns
115
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
+ #
116
133
  # Note: depending on your database connector, the result returned by this
117
- # method may be manually memory managed. Consider using the exec_query
134
+ # method may be manually memory managed. Consider using #exec_query
118
135
  # wrapper instead.
119
- def execute(sql, name = nil)
120
- raise NotImplementedError
136
+ def execute(sql, name = nil, allow_retry: false)
137
+ internal_execute(sql, name, allow_retry: allow_retry)
121
138
  end
122
139
 
123
140
  # Executes +sql+ statement in the context of this connection using
124
141
  # +binds+ as the bind substitutes. +name+ is logged along with
125
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.
126
147
  def exec_query(sql, name = "SQL", binds = [], prepare: false)
127
- raise NotImplementedError
148
+ internal_exec_query(sql, name, binds, prepare: prepare)
128
149
  end
129
150
 
130
151
  # Executes insert +sql+ statement in the context of this connection using
131
152
  # +binds+ as the bind substitutes. +name+ is logged along with
132
153
  # the executed +sql+ statement.
133
- def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
134
- sql, binds = sql_for_insert(sql, pk, binds)
135
- 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)
136
160
  end
137
161
 
138
162
  # Executes delete +sql+ statement in the context of this connection using
139
163
  # +binds+ as the bind substitutes. +name+ is logged along with
140
164
  # the executed +sql+ statement.
141
165
  def exec_delete(sql, name = nil, binds = [])
142
- exec_query(sql, name, binds)
166
+ internal_exec_query(sql, name, binds)
143
167
  end
144
168
 
145
169
  # Executes update +sql+ statement in the context of this connection using
146
170
  # +binds+ as the bind substitutes. +name+ is logged along with
147
171
  # the executed +sql+ statement.
148
172
  def exec_update(sql, name = nil, binds = [])
149
- exec_query(sql, name, binds)
173
+ internal_exec_query(sql, name, binds)
174
+ end
175
+
176
+ def exec_insert_all(sql, name) # :nodoc:
177
+ internal_exec_query(sql, name)
178
+ end
179
+
180
+ def explain(arel, binds = [], options = []) # :nodoc:
181
+ raise NotImplementedError
150
182
  end
151
183
 
152
184
  # Executes an INSERT query and returns the new record's ID
@@ -157,9 +189,15 @@ module ActiveRecord
157
189
  #
158
190
  # If the next id was calculated in advance (as in Oracle), it should be
159
191
  # passed in as +id_value+.
160
- 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)
161
196
  sql, binds = to_sql_and_binds(arel, binds)
162
- 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
+
163
201
  id_value || last_inserted_id(value)
164
202
  end
165
203
  alias create insert
@@ -178,17 +216,18 @@ module ActiveRecord
178
216
 
179
217
  # Executes the truncate statement.
180
218
  def truncate(table_name, name = nil)
181
- execute(build_truncate_statements(table_name), name)
219
+ execute(build_truncate_statement(table_name), name)
182
220
  end
183
221
 
184
222
  def truncate_tables(*table_names) # :nodoc:
223
+ table_names -= [pool.schema_migration.table_name, pool.internal_metadata.table_name]
224
+
185
225
  return if table_names.empty?
186
226
 
187
227
  with_multi_statements do
188
228
  disable_referential_integrity do
189
- Array(build_truncate_statements(*table_names)).each do |sql|
190
- execute_batch(sql, "Truncate Tables")
191
- end
229
+ statements = build_truncate_statements(table_names)
230
+ execute_batch(statements, "Truncate Tables")
192
231
  end
193
232
  end
194
233
  end
@@ -196,17 +235,43 @@ module ActiveRecord
196
235
  # Runs the given block in a database transaction, and returns the result
197
236
  # of the block.
198
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
+ #
199
249
  # == Nested transactions support
200
250
  #
251
+ # #transaction calls can be nested. By default, this makes all database
252
+ # statements in the nested transaction block become part of the parent
253
+ # transaction. For example, the following behavior may be surprising:
254
+ #
255
+ # ActiveRecord::Base.transaction do
256
+ # Post.create(title: 'first')
257
+ # ActiveRecord::Base.transaction do
258
+ # Post.create(title: 'second')
259
+ # raise ActiveRecord::Rollback
260
+ # end
261
+ # end
262
+ #
263
+ # This creates both "first" and "second" posts. Reason is the
264
+ # ActiveRecord::Rollback exception in the nested block does not issue a
265
+ # ROLLBACK. Since these exceptions are captured in transaction blocks,
266
+ # the parent block does not see it and the real transaction is committed.
267
+ #
201
268
  # Most databases don't support true nested transactions. At the time of
202
269
  # writing, the only database that supports true nested transactions that
203
270
  # we're aware of, is MS-SQL.
204
271
  #
205
272
  # In order to get around this problem, #transaction will emulate the effect
206
273
  # of nested transactions, by using savepoints:
207
- # https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
208
- # Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
209
- # supports savepoints.
274
+ # https://dev.mysql.com/doc/refman/en/savepoint.html.
210
275
  #
211
276
  # It is safe to call this method if a database transaction is already open,
212
277
  # i.e. if #transaction is called within another #transaction block. In case
@@ -218,6 +283,24 @@ module ActiveRecord
218
283
  # - However, if +:requires_new+ is set, the block will be wrapped in a
219
284
  # database savepoint acting as a sub-transaction.
220
285
  #
286
+ # In order to get a ROLLBACK for the nested transaction you may ask for a
287
+ # real sub-transaction by passing <tt>requires_new: true</tt>.
288
+ # If anything goes wrong, the database rolls back to the beginning of
289
+ # the sub-transaction without rolling back the parent transaction.
290
+ # If we add it to the previous example:
291
+ #
292
+ # ActiveRecord::Base.transaction do
293
+ # Post.create(title: 'first')
294
+ # ActiveRecord::Base.transaction(requires_new: true) do
295
+ # Post.create(title: 'second')
296
+ # raise ActiveRecord::Rollback
297
+ # end
298
+ # end
299
+ #
300
+ # only post with title "first" is created.
301
+ #
302
+ # See ActiveRecord::Transactions to learn more.
303
+ #
221
304
  # === Caveats
222
305
  #
223
306
  # MySQL doesn't support DDL transactions. If you perform a DDL operation,
@@ -230,9 +313,9 @@ module ActiveRecord
230
313
  # #transaction will raise exceptions when it tries to release the
231
314
  # already-automatically-released savepoints:
232
315
  #
233
- # Model.connection.transaction do # BEGIN
234
- # Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
235
- # 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(...)
236
319
  # # active_record_1 now automatically released
237
320
  # end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
238
321
  # end
@@ -257,7 +340,7 @@ module ActiveRecord
257
340
  # semantics of these different levels:
258
341
  #
259
342
  # * https://www.postgresql.org/docs/current/static/transaction-iso.html
260
- # * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html
343
+ # * https://dev.mysql.com/doc/refman/en/set-transaction.html
261
344
  #
262
345
  # An ActiveRecord::TransactionIsolationError will be raised if:
263
346
  #
@@ -265,43 +348,64 @@ module ActiveRecord
265
348
  # * You are joining an existing open transaction
266
349
  # * You are creating a nested (savepoint) transaction
267
350
  #
268
- # The mysql2 and postgresql adapters support setting the transaction
351
+ # The mysql2, trilogy, and postgresql adapters support setting the transaction
269
352
  # isolation level.
270
- 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)
271
355
  if !requires_new && current_transaction.joinable?
272
356
  if isolation
273
357
  raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
274
358
  end
275
- yield
359
+ yield current_transaction.user_transaction
276
360
  else
277
- transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable) { yield }
361
+ transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable, &block)
278
362
  end
279
363
  rescue ActiveRecord::Rollback
280
364
  # rollbacks are silently swallowed
281
365
  end
282
366
 
283
- attr_reader :transaction_manager #:nodoc:
367
+ attr_reader :transaction_manager # :nodoc:
284
368
 
285
369
  delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
286
370
  :commit_transaction, :rollback_transaction, :materialize_transactions,
287
- :disable_lazy_transactions!, :enable_lazy_transactions!, to: :transaction_manager
371
+ :disable_lazy_transactions!, :enable_lazy_transactions!, :dirty_current_transaction,
372
+ to: :transaction_manager
373
+
374
+ def mark_transaction_written_if_write(sql) # :nodoc:
375
+ transaction = current_transaction
376
+ if transaction.open?
377
+ transaction.written ||= write_query?(sql)
378
+ end
379
+ end
288
380
 
289
381
  def transaction_open?
290
382
  current_transaction.open?
291
383
  end
292
384
 
293
- 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
+
294
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
295
403
  end
296
404
 
297
405
  # Register a record with the current transaction so that its after_commit and after_rollback callbacks
298
406
  # can be called.
299
- def add_transaction_record(record)
300
- current_transaction.add_record(record)
301
- end
302
-
303
- def transaction_state
304
- current_transaction.state
407
+ def add_transaction_record(record, ensure_finalize = true)
408
+ current_transaction.add_record(record, ensure_finalize)
305
409
  end
306
410
 
307
411
  # Begins the transaction (and turns off auto-committing).
@@ -330,9 +434,17 @@ module ActiveRecord
330
434
  # done if the transaction block raises an exception or returns false.
331
435
  def rollback_db_transaction
332
436
  exec_rollback_db_transaction
437
+ rescue ActiveRecord::ConnectionNotEstablished, ActiveRecord::ConnectionFailed
438
+ # Connection's gone; that counts as a rollback
333
439
  end
334
440
 
335
- def exec_rollback_db_transaction() end #:nodoc:
441
+ def exec_rollback_db_transaction() end # :nodoc:
442
+
443
+ def restart_db_transaction
444
+ exec_restart_db_transaction
445
+ end
446
+
447
+ def exec_restart_db_transaction() end # :nodoc:
336
448
 
337
449
  def rollback_to_savepoint(name = nil)
338
450
  exec_rollback_to_savepoint(name)
@@ -348,10 +460,10 @@ module ActiveRecord
348
460
  end
349
461
 
350
462
  # Inserts the given fixture into the table. Overridden in adapters that require
351
- # something beyond a simple insert (eg. Oracle).
352
- # Most of adapters should implement `insert_fixtures_set` that leverages bulk SQL insert.
463
+ # something beyond a simple insert (e.g. Oracle).
464
+ # Most of adapters should implement +insert_fixtures_set+ that leverages bulk SQL insert.
353
465
  # We keep this method to provide fallback
354
- # for databases like sqlite that do not support bulk inserts.
466
+ # for databases like SQLite that do not support bulk inserts.
355
467
  def insert_fixture(fixture, table_name)
356
468
  execute(build_fixture_sql(Array.wrap(fixture), table_name), "Fixture Insert")
357
469
  end
@@ -359,14 +471,12 @@ module ActiveRecord
359
471
  def insert_fixtures_set(fixture_set, tables_to_delete = [])
360
472
  fixture_inserts = build_fixture_statements(fixture_set)
361
473
  table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" }
362
- total_sql = Array(combine_multi_statements(table_deletes + fixture_inserts))
474
+ statements = table_deletes + fixture_inserts
363
475
 
364
476
  with_multi_statements do
365
- disable_referential_integrity do
366
- transaction(requires_new: true) do
367
- total_sql.each do |sql|
368
- execute_batch(sql, "Fixtures Load")
369
- end
477
+ transaction(requires_new: true) do
478
+ disable_referential_integrity do
479
+ execute_batch(statements, "Fixtures Load")
370
480
  end
371
481
  end
372
482
  end
@@ -401,9 +511,41 @@ module ActiveRecord
401
511
  end
402
512
  end
403
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
+
404
531
  private
405
- def execute_batch(sql, name = nil)
406
- execute(sql, name)
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
+
541
+ def execute_batch(statements, name = nil)
542
+ statements.each do |statement|
543
+ internal_execute(statement, name)
544
+ end
545
+ end
546
+
547
+ def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
548
+ raise NotImplementedError
407
549
  end
408
550
 
409
551
  DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
@@ -414,7 +556,7 @@ module ActiveRecord
414
556
  end
415
557
 
416
558
  def build_fixture_sql(fixtures, table_name)
417
- columns = schema_cache.columns_hash(table_name)
559
+ columns = schema_cache.columns_hash(table_name).reject { |_, column| supports_virtual_columns? && column.virtual? }
418
560
 
419
561
  values_list = fixtures.map do |fixture|
420
562
  fixture = fixture.stringify_keys
@@ -435,8 +577,7 @@ module ActiveRecord
435
577
  end
436
578
 
437
579
  table = Arel::Table.new(table_name)
438
- manager = Arel::InsertManager.new
439
- manager.into(table)
580
+ manager = Arel::InsertManager.new(table)
440
581
 
441
582
  if values_list.size == 1
442
583
  values = values_list.shift
@@ -453,21 +594,24 @@ module ActiveRecord
453
594
  end
454
595
 
455
596
  manager.values = manager.create_values_list(values_list)
456
- manager.to_sql
597
+ visitor.compile(manager.ast)
457
598
  end
458
599
 
459
600
  def build_fixture_statements(fixture_set)
460
- fixture_set.map do |table_name, fixtures|
601
+ fixture_set.filter_map do |table_name, fixtures|
461
602
  next if fixtures.empty?
462
603
  build_fixture_sql(fixtures, table_name)
463
- end.compact
604
+ end
605
+ end
606
+
607
+ def build_truncate_statement(table_name)
608
+ "TRUNCATE TABLE #{quote_table_name(table_name)}"
464
609
  end
465
610
 
466
- def build_truncate_statements(*table_names)
467
- truncate_tables = table_names.map do |table_name|
468
- "TRUNCATE TABLE #{quote_table_name(table_name)}"
611
+ def build_truncate_statements(table_names)
612
+ table_names.map do |table_name|
613
+ build_truncate_statement(table_name)
469
614
  end
470
- combine_multi_statements(truncate_tables)
471
615
  end
472
616
 
473
617
  def with_multi_statements
@@ -479,15 +623,49 @@ module ActiveRecord
479
623
  end
480
624
 
481
625
  # Returns an ActiveRecord::Result instance.
482
- def select(sql, name = nil, binds = [])
483
- exec_query(sql, name, binds, prepare: false)
484
- 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
485
631
 
486
- def select_prepared(sql, name = nil, binds = [])
487
- 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
488
653
  end
489
654
 
490
- 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
+
491
669
  [sql, binds]
492
670
  end
493
671
 
@@ -495,6 +673,10 @@ module ActiveRecord
495
673
  single_value_from_rows(result.rows)
496
674
  end
497
675
 
676
+ def returning_column_values(result)
677
+ [last_inserted_id(result)]
678
+ end
679
+
498
680
  def single_value_from_rows(rows)
499
681
  row = rows.first
500
682
  row && row.first
@@ -507,6 +689,12 @@ module ActiveRecord
507
689
  relation
508
690
  end
509
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
510
698
  end
511
699
  end
512
700
  end