activerecord 6.1.7 → 7.2.2

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 (333) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +616 -1290
  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 +19 -8
  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 +30 -27
  30. data/lib/active_record/associations/join_dependency.rb +28 -20
  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 +429 -522
  40. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  41. data/lib/active_record/attribute_assignment.rb +1 -5
  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 +15 -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 +57 -54
  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 +19 -35
  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 +325 -604
  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 +230 -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 +378 -143
  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 +348 -165
  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 +403 -77
  108. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  109. data/lib/active_record/connection_adapters/postgresql_adapter.rb +520 -253
  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 +310 -253
  125. data/lib/active_record/counter_cache.rb +68 -34
  126. data/lib/active_record/database_configurations/connection_url_resolver.rb +10 -4
  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 +58 -0
  165. data/lib/active_record/enum.rb +170 -62
  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 +59 -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 +145 -158
  199. data/lib/active_record/nested_attributes.rb +61 -23
  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 +18 -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 +229 -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 +332 -103
  214. data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
  215. data/lib/active_record/relation/batches.rb +200 -65
  216. data/lib/active_record/relation/calculations.rb +301 -112
  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 +870 -163
  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 +6 -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 +288 -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 +65 -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/sqlite.rb +25 -0
  317. data/lib/arel/visitors/to_sql.rb +170 -36
  318. data/lib/arel/visitors/visitor.rb +2 -2
  319. data/lib/arel.rb +23 -4
  320. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  321. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  322. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  323. data/lib/rails/generators/active_record/migration.rb +3 -1
  324. data/lib/rails/generators/active_record/model/USAGE +113 -0
  325. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  326. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  327. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  328. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  329. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  330. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  331. metadata +103 -17
  332. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  333. data/lib/active_record/null_relation.rb +0 -67
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/string/access"
4
- require "digest/sha2"
4
+ require "openssl"
5
5
 
6
6
  module ActiveRecord
7
7
  module ConnectionAdapters # :nodoc:
@@ -29,7 +29,7 @@ module ActiveRecord
29
29
  table_name[0...table_alias_length].tr(".", "_")
30
30
  end
31
31
 
32
- # Returns the relation names useable to back Active Record models.
32
+ # Returns the relation names usable to back Active Record models.
33
33
  # For most adapters this means all #tables and #views.
34
34
  def data_sources
35
35
  query_values(data_source_sql, "SCHEMA")
@@ -96,25 +96,19 @@ module ActiveRecord
96
96
  # # Check an index with a custom name exists
97
97
  # index_exists?(:suppliers, :company_id, name: "idx_company_id")
98
98
  #
99
+ # # Check a valid index exists (PostgreSQL only)
100
+ # index_exists?(:suppliers, :company_id, valid: true)
101
+ #
99
102
  def index_exists?(table_name, column_name, **options)
100
- checks = []
101
-
102
- if column_name.present?
103
- column_names = Array(column_name).map(&:to_s)
104
- checks << lambda { |i| Array(i.columns) == column_names }
105
- end
106
-
107
- checks << lambda { |i| i.unique } if options[:unique]
108
- checks << lambda { |i| i.name == options[:name].to_s } if options[:name]
109
-
110
- indexes(table_name).any? { |i| checks.all? { |check| check[i] } }
103
+ indexes(table_name).any? { |i| i.defined_for?(column_name, **options) }
111
104
  end
112
105
 
113
106
  # Returns an array of +Column+ objects for the table specified by +table_name+.
114
107
  def columns(table_name)
115
108
  table_name = table_name.to_s
116
- column_definitions(table_name).map do |field|
117
- new_column_from_field(table_name, field)
109
+ definitions = column_definitions(table_name)
110
+ definitions.map do |field|
111
+ new_column_from_field(table_name, field, definitions)
118
112
  end
119
113
  end
120
114
 
@@ -124,6 +118,9 @@ module ActiveRecord
124
118
  # column_exists?(:suppliers, :name)
125
119
  #
126
120
  # # Check a column exists of a particular type
121
+ # #
122
+ # # This works for standard non-casted types (eg. string) but is unreliable
123
+ # # for types that may get cast to something else (eg. char, bigint).
127
124
  # column_exists?(:suppliers, :name, :string)
128
125
  #
129
126
  # # Check a column exists with a specific definition
@@ -260,7 +257,7 @@ module ActiveRecord
260
257
  #
261
258
  # generates:
262
259
  #
263
- # CREATE TABLE order (
260
+ # CREATE TABLE orders (
264
261
  # product_id bigint NOT NULL,
265
262
  # client_id bigint NOT NULL
266
263
  # );
@@ -293,25 +290,15 @@ module ActiveRecord
293
290
  # SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id
294
291
  #
295
292
  # See also TableDefinition#column for details on how to create columns.
296
- def create_table(table_name, id: :primary_key, primary_key: nil, force: nil, **options)
297
- td = create_table_definition(table_name, **extract_table_options!(options))
293
+ def create_table(table_name, id: :primary_key, primary_key: nil, force: nil, **options, &block)
294
+ validate_create_table_options!(options)
295
+ validate_table_length!(table_name) unless options[:_uses_legacy_table_name]
298
296
 
299
- if id && !td.as
300
- pk = primary_key || Base.get_primary_key(table_name.to_s.singularize)
301
-
302
- if id.is_a?(Hash)
303
- options.merge!(id.except(:type))
304
- id = id.fetch(:type, :primary_key)
305
- end
306
-
307
- if pk.is_a?(Array)
308
- td.primary_keys pk
309
- else
310
- td.primary_key pk, id, **options
311
- end
297
+ if force && options.key?(:if_not_exists)
298
+ raise ArgumentError, "Options `:force` and `:if_not_exists` cannot be used simultaneously."
312
299
  end
313
300
 
314
- yield td if block_given?
301
+ td = build_create_table_definition(table_name, id: id, primary_key: primary_key, force: force, **options, &block)
315
302
 
316
303
  if force
317
304
  drop_table(table_name, force: force, if_exists: true)
@@ -319,7 +306,7 @@ module ActiveRecord
319
306
  schema_cache.clear_data_source_cache!(table_name.to_s)
320
307
  end
321
308
 
322
- result = execute schema_creation.accept td
309
+ result = execute schema_creation.accept(td)
323
310
 
324
311
  unless supports_indexes_in_create?
325
312
  td.indexes.each do |column_name, index_options|
@@ -340,6 +327,18 @@ module ActiveRecord
340
327
  result
341
328
  end
342
329
 
330
+ # Returns a TableDefinition object containing information about the table that would be created
331
+ # if the same arguments were passed to #create_table. See #create_table for information about
332
+ # passing a +table_name+, and other additional options that can be passed.
333
+ def build_create_table_definition(table_name, id: :primary_key, primary_key: nil, force: nil, **options)
334
+ table_definition = create_table_definition(table_name, **options.extract!(*valid_table_definition_options, :_skip_validate_options))
335
+ table_definition.set_primary_key(table_name, id, primary_key, **options.extract!(*valid_primary_key_options, :_skip_validate_options))
336
+
337
+ yield table_definition if block_given?
338
+
339
+ table_definition
340
+ end
341
+
343
342
  # Creates a new join table with the name created using the lexical order of the first two
344
343
  # arguments. These arguments can be a String or a Symbol.
345
344
  #
@@ -383,7 +382,7 @@ module ActiveRecord
383
382
 
384
383
  column_options.reverse_merge!(null: false, index: false)
385
384
 
386
- t1_ref, t2_ref = [table_1, table_2].map { |t| t.to_s.singularize }
385
+ t1_ref, t2_ref = [table_1, table_2].map { |t| reference_name_for_table(t) }
387
386
 
388
387
  create_table(join_table_name, **options.merge!(id: false)) do |td|
389
388
  td.references t1_ref, **column_options
@@ -392,15 +391,33 @@ module ActiveRecord
392
391
  end
393
392
  end
394
393
 
394
+ # Builds a TableDefinition object for a join table.
395
+ #
396
+ # This definition object contains information about the table that would be created
397
+ # if the same arguments were passed to #create_join_table. See #create_join_table for
398
+ # information about what arguments should be passed.
399
+ def build_create_join_table_definition(table_1, table_2, column_options: {}, **options) # :nodoc:
400
+ join_table_name = find_join_table_name(table_1, table_2, options)
401
+ column_options.reverse_merge!(null: false, index: false)
402
+
403
+ t1_ref, t2_ref = [table_1, table_2].map { |t| reference_name_for_table(t) }
404
+
405
+ build_create_table_definition(join_table_name, **options.merge!(id: false)) do |td|
406
+ td.references t1_ref, **column_options
407
+ td.references t2_ref, **column_options
408
+ yield td if block_given?
409
+ end
410
+ end
411
+
395
412
  # Drops the join table specified by the given arguments.
396
- # See #create_join_table for details.
413
+ # See #create_join_table and #drop_table for details.
397
414
  #
398
415
  # Although this command ignores the block if one is given, it can be helpful
399
416
  # to provide one in a migration's +change+ method so it can be reverted.
400
417
  # In that case, the block will be used by #create_join_table.
401
418
  def drop_join_table(table_1, table_2, **options)
402
419
  join_table_name = find_join_table_name(table_1, table_2, options)
403
- drop_table(join_table_name)
420
+ drop_table(join_table_name, **options)
404
421
  end
405
422
 
406
423
  # A block for changing columns in +table+.
@@ -481,13 +498,13 @@ module ActiveRecord
481
498
  # end
482
499
  #
483
500
  # See also Table for details on all of the various column transformations.
484
- def change_table(table_name, **options)
501
+ def change_table(table_name, base = self, **options)
485
502
  if supports_bulk_alter? && options[:bulk]
486
503
  recorder = ActiveRecord::Migration::CommandRecorder.new(self)
487
504
  yield update_table_definition(table_name, recorder)
488
505
  bulk_change_table(table_name, recorder.commands)
489
506
  else
490
- yield update_table_definition(table_name, self)
507
+ yield update_table_definition(table_name, base)
491
508
  end
492
509
  end
493
510
 
@@ -495,7 +512,7 @@ module ActiveRecord
495
512
  #
496
513
  # rename_table('octopuses', 'octopi')
497
514
  #
498
- def rename_table(table_name, new_name)
515
+ def rename_table(table_name, new_name, **)
499
516
  raise NotImplementedError, "rename_table is not implemented"
500
517
  end
501
518
 
@@ -518,24 +535,31 @@ module ActiveRecord
518
535
 
519
536
  # Add a new +type+ column named +column_name+ to +table_name+.
520
537
  #
538
+ # See {ActiveRecord::ConnectionAdapters::TableDefinition.column}[rdoc-ref:ActiveRecord::ConnectionAdapters::TableDefinition#column].
539
+ #
521
540
  # The +type+ parameter is normally one of the migrations native types,
522
541
  # which is one of the following:
523
542
  # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
524
543
  # <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:numeric</tt>,
525
544
  # <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
526
- # <tt>:binary</tt>, <tt>:boolean</tt>.
545
+ # <tt>:binary</tt>, <tt>:blob</tt>, <tt>:boolean</tt>.
527
546
  #
528
547
  # You may use a type not in this list as long as it is supported by your
529
548
  # database (for example, "polygon" in MySQL), but this will not be database
530
549
  # agnostic and should usually be avoided.
531
550
  #
532
551
  # Available options are (none of these exists by default):
552
+ # * <tt>:comment</tt> -
553
+ # Specifies the comment for the column. This option is ignored by some backends.
554
+ # * <tt>:collation</tt> -
555
+ # Specifies the collation for a <tt>:string</tt> or <tt>:text</tt> column.
556
+ # If not specified, the column will have the same collation as the table.
557
+ # * <tt>:default</tt> -
558
+ # The column's default value. Use +nil+ for +NULL+.
533
559
  # * <tt>:limit</tt> -
534
560
  # Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
535
- # and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, and <tt>:integer</tt> columns.
561
+ # and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, <tt>:blob</tt>, and <tt>:integer</tt> columns.
536
562
  # This option is ignored by some backends.
537
- # * <tt>:default</tt> -
538
- # The column's default value. Use +nil+ for +NULL+.
539
563
  # * <tt>:null</tt> -
540
564
  # Allows or disallows +NULL+ values in the column.
541
565
  # * <tt>:precision</tt> -
@@ -543,11 +567,6 @@ module ActiveRecord
543
567
  # <tt>:datetime</tt>, and <tt>:time</tt> columns.
544
568
  # * <tt>:scale</tt> -
545
569
  # Specifies the scale for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
546
- # * <tt>:collation</tt> -
547
- # Specifies the collation for a <tt>:string</tt> or <tt>:text</tt> column. If not specified, the
548
- # column will have the same collation as the table.
549
- # * <tt>:comment</tt> -
550
- # Specifies the comment for the column. This option is ignored by some backends.
551
570
  # * <tt>:if_not_exists</tt> -
552
571
  # Specifies if the column already exists to not try to re-add it. This will avoid
553
572
  # duplicate column errors.
@@ -563,7 +582,7 @@ module ActiveRecord
563
582
  # * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
564
583
  # <tt>:precision</tt>, and makes no comments about the requirements of
565
584
  # <tt>:precision</tt>.
566
- # * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
585
+ # * MySQL: <tt>:precision</tt> [1..65], <tt>:scale</tt> [0..30].
567
586
  # Default is (10,0).
568
587
  # * PostgreSQL: <tt>:precision</tt> [1..infinity],
569
588
  # <tt>:scale</tt> [0..infinity]. No default.
@@ -604,11 +623,10 @@ module ActiveRecord
604
623
  # # Ignores the method call if the column exists
605
624
  # add_column(:shapes, :triangle, 'polygon', if_not_exists: true)
606
625
  def add_column(table_name, column_name, type, **options)
607
- return if options[:if_not_exists] == true && column_exists?(table_name, column_name, type)
626
+ add_column_def = build_add_column_definition(table_name, column_name, type, **options)
627
+ return unless add_column_def
608
628
 
609
- at = create_alter_table table_name
610
- at.add_column(column_name, type, **options)
611
- execute schema_creation.accept at
629
+ execute schema_creation.accept(add_column_def)
612
630
  end
613
631
 
614
632
  def add_columns(table_name, *column_names, type:, **options) # :nodoc:
@@ -617,6 +635,25 @@ module ActiveRecord
617
635
  end
618
636
  end
619
637
 
638
+ # Builds an AlterTable object for adding a column to a table.
639
+ #
640
+ # This definition object contains information about the column that would be created
641
+ # if the same arguments were passed to #add_column. See #add_column for information about
642
+ # passing a +table_name+, +column_name+, +type+ and other options that can be passed.
643
+ def build_add_column_definition(table_name, column_name, type, **options) # :nodoc:
644
+ return if options[:if_not_exists] == true && column_exists?(table_name, column_name)
645
+
646
+ if supports_datetime_with_precision?
647
+ if type == :datetime && !options.key?(:precision)
648
+ options[:precision] = 6
649
+ end
650
+ end
651
+
652
+ alter_table = create_alter_table(table_name)
653
+ alter_table.add_column(column_name, type, **options)
654
+ alter_table
655
+ end
656
+
620
657
  # Removes the given columns from the table definition.
621
658
  #
622
659
  # remove_columns(:suppliers, :qualification, :experience)
@@ -629,9 +666,8 @@ module ActiveRecord
629
666
  raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)")
630
667
  end
631
668
 
632
- column_names.each do |column_name|
633
- remove_column(table_name, column_name, type, **options)
634
- end
669
+ remove_column_fragments = remove_columns_for_alter(table_name, *column_names, type: type, **options)
670
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{remove_column_fragments.join(', ')}"
635
671
  end
636
672
 
637
673
  # Removes the column from the table definition.
@@ -641,11 +677,12 @@ module ActiveRecord
641
677
  # The +type+ and +options+ parameters will be ignored if present. It can be helpful
642
678
  # to provide these in a migration's +change+ method so it can be reverted.
643
679
  # In that case, +type+ and +options+ will be used by #add_column.
644
- # Indexes on the column are automatically removed.
680
+ # Depending on the database you're using, indexes using this column may be
681
+ # automatically removed or modified to remove this column from the index.
645
682
  #
646
683
  # If the options provided include an +if_exists+ key, it will be used to check if the
647
684
  # column does not exist. This will silently ignore the migration rather than raising
648
- # if the column was already used.
685
+ # if the column was already removed.
649
686
  #
650
687
  # remove_column(:suppliers, :qualification, if_exists: true)
651
688
  def remove_column(table_name, column_name, type = nil, **options)
@@ -682,6 +719,15 @@ module ActiveRecord
682
719
  raise NotImplementedError, "change_column_default is not implemented"
683
720
  end
684
721
 
722
+ # Builds a ChangeColumnDefaultDefinition object.
723
+ #
724
+ # This definition object contains information about the column change that would occur
725
+ # if the same arguments were passed to #change_column_default. See #change_column_default for
726
+ # information about passing a +table_name+, +column_name+, +type+ and other options that can be passed.
727
+ def build_change_column_default_definition(table_name, column_name, default_or_changes) # :nodoc:
728
+ raise NotImplementedError, "build_change_column_default_definition is not implemented"
729
+ end
730
+
685
731
  # Sets or removes a <tt>NOT NULL</tt> constraint on a column. The +null+ flag
686
732
  # indicates whether the value can be +NULL+. For example
687
733
  #
@@ -766,7 +812,7 @@ module ActiveRecord
766
812
  #
767
813
  # CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
768
814
  #
769
- # Note: SQLite doesn't support index length.
815
+ # Note: only supported by MySQL
770
816
  #
771
817
  # ====== Creating an index with a sort order (desc or asc, asc is the default)
772
818
  #
@@ -788,6 +834,16 @@ module ActiveRecord
788
834
  #
789
835
  # Note: Partial indexes are only supported for PostgreSQL and SQLite.
790
836
  #
837
+ # ====== Creating an index that includes additional columns
838
+ #
839
+ # add_index(:accounts, :branch_id, include: :party_id)
840
+ #
841
+ # generates:
842
+ #
843
+ # CREATE INDEX index_accounts_on_branch_id ON accounts USING btree(branch_id) INCLUDE (party_id)
844
+ #
845
+ # Note: only supported by PostgreSQL.
846
+ #
791
847
  # ====== Creating an index with a specific method
792
848
  #
793
849
  # add_index(:developers, :name, using: 'btree')
@@ -825,20 +881,31 @@ module ActiveRecord
825
881
  # ====== Creating an index with a specific algorithm
826
882
  #
827
883
  # add_index(:developers, :name, algorithm: :concurrently)
828
- # # CREATE INDEX CONCURRENTLY developers_on_name on developers (name)
884
+ # # CREATE INDEX CONCURRENTLY developers_on_name on developers (name) -- PostgreSQL
829
885
  #
830
- # Note: only supported by PostgreSQL.
886
+ # add_index(:developers, :name, algorithm: :inplace)
887
+ # # CREATE INDEX `index_developers_on_name` ON `developers` (`name`) ALGORITHM = INPLACE -- MySQL
888
+ #
889
+ # Note: only supported by PostgreSQL and MySQL.
831
890
  #
832
891
  # Concurrently adding an index is not supported in a transaction.
833
892
  #
834
893
  # For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
835
894
  def add_index(table_name, column_name, **options)
836
- index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
837
-
838
- create_index = CreateIndexDefinition.new(index, algorithm, if_not_exists)
895
+ create_index = build_create_index_definition(table_name, column_name, **options)
839
896
  execute schema_creation.accept(create_index)
840
897
  end
841
898
 
899
+ # Builds a CreateIndexDefinition object.
900
+ #
901
+ # This definition object contains information about the index that would be created
902
+ # if the same arguments were passed to #add_index. See #add_index for information about
903
+ # passing a +table_name+, +column_name+, and other additional options that can be passed.
904
+ def build_create_index_definition(table_name, column_name, **options) # :nodoc:
905
+ index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
906
+ CreateIndexDefinition.new(index, algorithm, if_not_exists)
907
+ end
908
+
842
909
  # Removes the given index from the table.
843
910
  #
844
911
  # Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
@@ -901,10 +968,14 @@ module ActiveRecord
901
968
  remove_index(table_name, name: old_name)
902
969
  end
903
970
 
904
- def index_name(table_name, options) #:nodoc:
971
+ def index_name(table_name, options) # :nodoc:
905
972
  if Hash === options
906
973
  if options[:column]
907
- "index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
974
+ if options[:_uses_legacy_index_name]
975
+ "index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
976
+ else
977
+ generate_index_name(table_name, options[:column])
978
+ end
908
979
  elsif options[:name]
909
980
  options[:name]
910
981
  else
@@ -924,7 +995,6 @@ module ActiveRecord
924
995
  # Adds a reference. The reference column is a bigint by default,
925
996
  # the <tt>:type</tt> option can be used to specify a different type.
926
997
  # Optionally adds a +_type+ column, if <tt>:polymorphic</tt> option is provided.
927
- # #add_reference and #add_belongs_to are acceptable.
928
998
  #
929
999
  # The +options+ hash can include the following keys:
930
1000
  # [<tt>:type</tt>]
@@ -970,12 +1040,11 @@ module ActiveRecord
970
1040
  # add_reference(:products, :supplier, foreign_key: { to_table: :firms })
971
1041
  #
972
1042
  def add_reference(table_name, ref_name, **options)
973
- ReferenceDefinition.new(ref_name, **options).add_to(update_table_definition(table_name, self))
1043
+ ReferenceDefinition.new(ref_name, **options).add(table_name, self)
974
1044
  end
975
1045
  alias :add_belongs_to :add_reference
976
1046
 
977
1047
  # Removes the reference(s). Also removes a +type+ column if one exists.
978
- # #remove_reference and #remove_belongs_to are acceptable.
979
1048
  #
980
1049
  # ====== Remove the reference
981
1050
  #
@@ -990,19 +1059,21 @@ module ActiveRecord
990
1059
  # remove_reference(:products, :user, foreign_key: true)
991
1060
  #
992
1061
  def remove_reference(table_name, ref_name, foreign_key: false, polymorphic: false, **options)
1062
+ conditional_options = options.slice(:if_exists, :if_not_exists)
1063
+
993
1064
  if foreign_key
994
1065
  reference_name = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
995
1066
  if foreign_key.is_a?(Hash)
996
- foreign_key_options = foreign_key
1067
+ foreign_key_options = foreign_key.merge(conditional_options)
997
1068
  else
998
- foreign_key_options = { to_table: reference_name }
1069
+ foreign_key_options = { to_table: reference_name, **conditional_options }
999
1070
  end
1000
1071
  foreign_key_options[:column] ||= "#{ref_name}_id"
1001
1072
  remove_foreign_key(table_name, **foreign_key_options)
1002
1073
  end
1003
1074
 
1004
- remove_column(table_name, "#{ref_name}_id")
1005
- remove_column(table_name, "#{ref_name}_type") if polymorphic
1075
+ remove_column(table_name, "#{ref_name}_id", **conditional_options)
1076
+ remove_column(table_name, "#{ref_name}_type", **conditional_options) if polymorphic
1006
1077
  end
1007
1078
  alias :remove_belongs_to :remove_reference
1008
1079
 
@@ -1027,6 +1098,10 @@ module ActiveRecord
1027
1098
  #
1028
1099
  # ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
1029
1100
  #
1101
+ # ====== Creating a foreign key, ignoring method call if the foreign key exists
1102
+ #
1103
+ # add_foreign_key(:articles, :authors, if_not_exists: true)
1104
+ #
1030
1105
  # ====== Creating a foreign key on a specific column
1031
1106
  #
1032
1107
  # add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
@@ -1035,6 +1110,16 @@ module ActiveRecord
1035
1110
  #
1036
1111
  # ALTER TABLE "articles" ADD CONSTRAINT fk_rails_58ca3d3a82 FOREIGN KEY ("author_id") REFERENCES "users" ("lng_id")
1037
1112
  #
1113
+ # ====== Creating a composite foreign key
1114
+ #
1115
+ # Assuming "carts" table has "(shop_id, user_id)" as a primary key.
1116
+ #
1117
+ # add_foreign_key :orders, :carts, primary_key: [:shop_id, :user_id]
1118
+ #
1119
+ # generates:
1120
+ #
1121
+ # ALTER TABLE "orders" ADD CONSTRAINT fk_rails_6f5e4cb3a4 FOREIGN KEY ("cart_shop_id", "cart_user_id") REFERENCES "carts" ("shop_id", "user_id")
1122
+ #
1038
1123
  # ====== Creating a cascading foreign key
1039
1124
  #
1040
1125
  # add_foreign_key :articles, :authors, on_delete: :cascade
@@ -1045,19 +1130,28 @@ module ActiveRecord
1045
1130
  #
1046
1131
  # The +options+ hash can include the following keys:
1047
1132
  # [<tt>:column</tt>]
1048
- # The foreign key column name on +from_table+. Defaults to <tt>to_table.singularize + "_id"</tt>
1133
+ # The foreign key column name on +from_table+. Defaults to <tt>to_table.singularize + "_id"</tt>.
1134
+ # Pass an array to create a composite foreign key.
1049
1135
  # [<tt>:primary_key</tt>]
1050
1136
  # The primary key column name on +to_table+. Defaults to +id+.
1137
+ # Pass an array to create a composite foreign key.
1051
1138
  # [<tt>:name</tt>]
1052
1139
  # The constraint name. Defaults to <tt>fk_rails_<identifier></tt>.
1053
1140
  # [<tt>:on_delete</tt>]
1054
- # Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
1141
+ # Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+, and +:restrict+
1055
1142
  # [<tt>:on_update</tt>]
1056
- # Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
1143
+ # Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+, and +:restrict+
1144
+ # [<tt>:if_not_exists</tt>]
1145
+ # Specifies if the foreign key already exists to not try to re-add it. This will avoid
1146
+ # duplicate column errors.
1057
1147
  # [<tt>:validate</tt>]
1058
1148
  # (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
1149
+ # [<tt>:deferrable</tt>]
1150
+ # (PostgreSQL only) Specify whether or not the foreign key should be deferrable. Valid values are booleans or
1151
+ # +:deferred+ or +:immediate+ to specify the default behavior. Defaults to +false+.
1059
1152
  def add_foreign_key(from_table, to_table, **options)
1060
- return unless supports_foreign_keys?
1153
+ return unless use_foreign_keys?
1154
+ return if options[:if_not_exists] == true && foreign_key_exists?(from_table, to_table, **options.slice(:column))
1061
1155
 
1062
1156
  options = foreign_key_options(from_table, to_table, options)
1063
1157
  at = create_alter_table from_table
@@ -1087,12 +1181,18 @@ module ActiveRecord
1087
1181
  #
1088
1182
  # remove_foreign_key :accounts, name: :special_fk_name
1089
1183
  #
1184
+ # Checks if the foreign key exists before trying to remove it. Will silently ignore indexes that
1185
+ # don't exist.
1186
+ #
1187
+ # remove_foreign_key :accounts, :branches, if_exists: true
1188
+ #
1090
1189
  # The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key
1091
1190
  # with an addition of
1092
1191
  # [<tt>:to_table</tt>]
1093
1192
  # The name of the table that contains the referenced primary key.
1094
1193
  def remove_foreign_key(from_table, to_table = nil, **options)
1095
- return unless supports_foreign_keys?
1194
+ return unless use_foreign_keys?
1195
+ return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table)
1096
1196
 
1097
1197
  fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
1098
1198
 
@@ -1117,15 +1217,33 @@ module ActiveRecord
1117
1217
  foreign_key_for(from_table, to_table: to_table, **options).present?
1118
1218
  end
1119
1219
 
1120
- def foreign_key_column_for(table_name) # :nodoc:
1220
+ def foreign_key_column_for(table_name, column_name) # :nodoc:
1121
1221
  name = strip_table_name_prefix_and_suffix(table_name)
1122
- "#{name.singularize}_id"
1222
+ "#{name.singularize}_#{column_name}"
1123
1223
  end
1124
1224
 
1125
1225
  def foreign_key_options(from_table, to_table, options) # :nodoc:
1126
1226
  options = options.dup
1127
- options[:column] ||= foreign_key_column_for(to_table)
1227
+
1228
+ if options[:primary_key].is_a?(Array)
1229
+ options[:column] ||= options[:primary_key].map do |pk_column|
1230
+ foreign_key_column_for(to_table, pk_column)
1231
+ end
1232
+ else
1233
+ options[:column] ||= foreign_key_column_for(to_table, "id")
1234
+ end
1235
+
1128
1236
  options[:name] ||= foreign_key_name(from_table, options)
1237
+
1238
+ if options[:column].is_a?(Array) || options[:primary_key].is_a?(Array)
1239
+ if Array(options[:primary_key]).size != Array(options[:column]).size
1240
+ raise ArgumentError, <<~MSG.squish
1241
+ For composite primary keys, specify :column and :primary_key, where
1242
+ :column must reference all the :primary_key columns from #{to_table.inspect}
1243
+ MSG
1244
+ end
1245
+ end
1246
+
1129
1247
  options
1130
1248
  end
1131
1249
 
@@ -1147,12 +1265,16 @@ module ActiveRecord
1147
1265
  # The +options+ hash can include the following keys:
1148
1266
  # [<tt>:name</tt>]
1149
1267
  # The constraint name. Defaults to <tt>chk_rails_<identifier></tt>.
1268
+ # [<tt>:if_not_exists</tt>]
1269
+ # Silently ignore if the constraint already exists, rather than raise an error.
1150
1270
  # [<tt>:validate</tt>]
1151
1271
  # (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
1152
- def add_check_constraint(table_name, expression, **options)
1272
+ def add_check_constraint(table_name, expression, if_not_exists: false, **options)
1153
1273
  return unless supports_check_constraints?
1154
1274
 
1155
1275
  options = check_constraint_options(table_name, expression, options)
1276
+ return if if_not_exists && check_constraint_exists?(table_name, **options)
1277
+
1156
1278
  at = create_alter_table(table_name)
1157
1279
  at.add_check_constraint(expression, options)
1158
1280
 
@@ -1165,16 +1287,24 @@ module ActiveRecord
1165
1287
  options
1166
1288
  end
1167
1289
 
1168
- # Removes the given check constraint from the table.
1290
+ # Removes the given check constraint from the table. Removing a check constraint
1291
+ # that does not exist will raise an error.
1169
1292
  #
1170
1293
  # remove_check_constraint :products, name: "price_check"
1171
1294
  #
1295
+ # To silently ignore a non-existent check constraint rather than raise an error,
1296
+ # use the +if_exists+ option.
1297
+ #
1298
+ # remove_check_constraint :products, name: "price_check", if_exists: true
1299
+ #
1172
1300
  # The +expression+ parameter will be ignored if present. It can be helpful
1173
1301
  # to provide this in a migration's +change+ method so it can be reverted.
1174
1302
  # In that case, +expression+ will be used by #add_check_constraint.
1175
- def remove_check_constraint(table_name, expression = nil, **options)
1303
+ def remove_check_constraint(table_name, expression = nil, if_exists: false, **options)
1176
1304
  return unless supports_check_constraints?
1177
1305
 
1306
+ return if if_exists && !check_constraint_exists?(table_name, **options)
1307
+
1178
1308
  chk_name_to_delete = check_constraint_for!(table_name, expression: expression, **options).name
1179
1309
 
1180
1310
  at = create_alter_table(table_name)
@@ -1183,8 +1313,20 @@ module ActiveRecord
1183
1313
  execute schema_creation.accept(at)
1184
1314
  end
1185
1315
 
1316
+
1317
+ # Checks to see if a check constraint exists on a table for a given check constraint definition.
1318
+ #
1319
+ # check_constraint_exists?(:products, name: "price_check")
1320
+ #
1321
+ def check_constraint_exists?(table_name, **options)
1322
+ if !options.key?(:name) && !options.key?(:expression)
1323
+ raise ArgumentError, "At least one of :name or :expression must be supplied"
1324
+ end
1325
+ check_constraint_for(table_name, **options).present?
1326
+ end
1327
+
1186
1328
  def dump_schema_information # :nodoc:
1187
- versions = schema_migration.all_versions
1329
+ versions = pool.schema_migration.versions
1188
1330
  insert_versions_sql(versions) if versions.any?
1189
1331
  end
1190
1332
 
@@ -1194,8 +1336,9 @@ module ActiveRecord
1194
1336
 
1195
1337
  def assume_migrated_upto_version(version)
1196
1338
  version = version.to_i
1197
- sm_table = quote_table_name(schema_migration.table_name)
1339
+ sm_table = quote_table_name(pool.schema_migration.table_name)
1198
1340
 
1341
+ migration_context = pool.migration_context
1199
1342
  migrated = migration_context.get_all_versions
1200
1343
  versions = migration_context.migrations.map(&:version)
1201
1344
 
@@ -1256,20 +1399,39 @@ module ActiveRecord
1256
1399
  columns
1257
1400
  end
1258
1401
 
1402
+ def distinct_relation_for_primary_key(relation) # :nodoc:
1403
+ primary_key_columns = Array(relation.primary_key).map do |column|
1404
+ visitor.compile(relation.table[column])
1405
+ end
1406
+
1407
+ values = columns_for_distinct(
1408
+ primary_key_columns,
1409
+ relation.order_values
1410
+ )
1411
+
1412
+ limited = relation.reselect(values).distinct!
1413
+ limited_ids = select_rows(limited.arel, "SQL").map do |results|
1414
+ results.last(Array(relation.primary_key).length) # ignores order values for MySQL and PostgreSQL
1415
+ end
1416
+
1417
+ if limited_ids.empty?
1418
+ relation.none!
1419
+ else
1420
+ relation.where!(**Array(relation.primary_key).zip(limited_ids.transpose).to_h)
1421
+ end
1422
+
1423
+ relation.limit_value = relation.offset_value = nil
1424
+ relation
1425
+ end
1426
+
1259
1427
  # Adds timestamps (+created_at+ and +updated_at+) columns to +table_name+.
1260
1428
  # Additional options (like +:null+) are forwarded to #add_column.
1261
1429
  #
1262
1430
  # add_timestamps(:suppliers, null: true)
1263
1431
  #
1264
1432
  def add_timestamps(table_name, **options)
1265
- options[:null] = false if options[:null].nil?
1266
-
1267
- if !options.key?(:precision) && supports_datetime_with_precision?
1268
- options[:precision] = 6
1269
- end
1270
-
1271
- add_column table_name, :created_at, :datetime, **options
1272
- add_column table_name, :updated_at, :datetime, **options
1433
+ fragments = add_timestamps_for_alter(table_name, **options)
1434
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{fragments.join(', ')}"
1273
1435
  end
1274
1436
 
1275
1437
  # Removes the timestamp columns (+created_at+ and +updated_at+) from the table definition.
@@ -1277,16 +1439,15 @@ module ActiveRecord
1277
1439
  # remove_timestamps(:suppliers)
1278
1440
  #
1279
1441
  def remove_timestamps(table_name, **options)
1280
- remove_column table_name, :updated_at
1281
- remove_column table_name, :created_at
1442
+ remove_columns table_name, :updated_at, :created_at
1282
1443
  end
1283
1444
 
1284
- def update_table_definition(table_name, base) #:nodoc:
1445
+ def update_table_definition(table_name, base) # :nodoc:
1285
1446
  Table.new(table_name, base)
1286
1447
  end
1287
1448
 
1288
1449
  def add_index_options(table_name, column_name, name: nil, if_not_exists: false, internal: false, **options) # :nodoc:
1289
- options.assert_valid_keys(:unique, :length, :order, :opclass, :where, :type, :using, :comment, :algorithm)
1450
+ options.assert_valid_keys(:unique, :length, :order, :opclass, :where, :type, :using, :comment, :algorithm, :include, :nulls_not_distinct)
1290
1451
 
1291
1452
  column_names = index_column_names(column_name)
1292
1453
 
@@ -1305,6 +1466,8 @@ module ActiveRecord
1305
1466
  where: options[:where],
1306
1467
  type: options[:type],
1307
1468
  using: options[:using],
1469
+ include: options[:include],
1470
+ nulls_not_distinct: options[:nulls_not_distinct],
1308
1471
  comment: options[:comment]
1309
1472
  )
1310
1473
 
@@ -1352,7 +1515,79 @@ module ActiveRecord
1352
1515
  SchemaDumper.create(self, options)
1353
1516
  end
1354
1517
 
1518
+ def use_foreign_keys?
1519
+ supports_foreign_keys? && foreign_keys_enabled?
1520
+ end
1521
+
1522
+ # Returns an instance of SchemaCreation, which can be used to visit a schema definition
1523
+ # object and return DDL.
1524
+ def schema_creation # :nodoc:
1525
+ SchemaCreation.new(self)
1526
+ end
1527
+
1528
+ def bulk_change_table(table_name, operations) # :nodoc:
1529
+ sql_fragments = []
1530
+ non_combinable_operations = []
1531
+
1532
+ operations.each do |command, args|
1533
+ table, arguments = args.shift, args
1534
+ method = :"#{command}_for_alter"
1535
+
1536
+ if respond_to?(method, true)
1537
+ sqls, procs = Array(send(method, table, *arguments)).partition { |v| v.is_a?(String) }
1538
+ sql_fragments.concat(sqls)
1539
+ non_combinable_operations.concat(procs)
1540
+ else
1541
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
1542
+ non_combinable_operations.each(&:call)
1543
+ sql_fragments = []
1544
+ non_combinable_operations = []
1545
+ send(command, table, *arguments)
1546
+ end
1547
+ end
1548
+
1549
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
1550
+ non_combinable_operations.each(&:call)
1551
+ end
1552
+
1553
+ def valid_table_definition_options # :nodoc:
1554
+ [:temporary, :if_not_exists, :options, :as, :comment, :charset, :collation]
1555
+ end
1556
+
1557
+ def valid_column_definition_options # :nodoc:
1558
+ ColumnDefinition::OPTION_NAMES
1559
+ end
1560
+
1561
+ def valid_primary_key_options # :nodoc:
1562
+ [:limit, :default, :precision]
1563
+ end
1564
+
1565
+ # Returns the maximum length of an index name in bytes.
1566
+ def max_index_name_size
1567
+ 62
1568
+ end
1569
+
1355
1570
  private
1571
+ def generate_index_name(table_name, column)
1572
+ name = "index_#{table_name}_on_#{Array(column) * '_and_'}"
1573
+ return name if name.bytesize <= max_index_name_size
1574
+
1575
+ # Fallback to short version, add hash to ensure uniqueness
1576
+ hashed_identifier = "_" + OpenSSL::Digest::SHA256.hexdigest(name).first(10)
1577
+ name = "idx_on_#{Array(column) * '_'}"
1578
+
1579
+ short_limit = max_index_name_size - hashed_identifier.bytesize
1580
+ short_name = name.mb_chars.limit(short_limit).to_s
1581
+
1582
+ "#{short_name}#{hashed_identifier}"
1583
+ end
1584
+
1585
+ def validate_change_column_null_argument!(value)
1586
+ unless value == true || value == false
1587
+ raise ArgumentError, "change_column_null expects a boolean value (true for NULL, false for NOT NULL). Got: #{value.inspect}"
1588
+ end
1589
+ end
1590
+
1356
1591
  def column_options_keys
1357
1592
  [:limit, :precision, :scale, :default, :null, :collation, :comment]
1358
1593
  end
@@ -1387,7 +1622,7 @@ module ActiveRecord
1387
1622
 
1388
1623
  checks = []
1389
1624
 
1390
- if !options.key?(:name) && column_name.is_a?(String) && /\W/.match?(column_name)
1625
+ if !options.key?(:name) && expression_column_name?(column_name)
1391
1626
  options[:name] = index_name(table_name, column_name)
1392
1627
  column_names = []
1393
1628
  else
@@ -1396,7 +1631,7 @@ module ActiveRecord
1396
1631
 
1397
1632
  checks << lambda { |i| i.name == options[:name].to_s } if options.key?(:name)
1398
1633
 
1399
- if column_names.present?
1634
+ if column_names.present? && !(options.key?(:name) && expression_column_name?(column_names))
1400
1635
  checks << lambda { |i| index_name(table_name, i.columns) == index_name(table_name, column_names) }
1401
1636
  end
1402
1637
 
@@ -1406,7 +1641,7 @@ module ActiveRecord
1406
1641
 
1407
1642
  if matching_indexes.count > 1
1408
1643
  raise ArgumentError, "Multiple indexes found on #{table_name} columns #{column_names}. " \
1409
- "Specify an index name from #{matching_indexes.map(&:name).join(', ')}"
1644
+ "Specify an index name from #{matching_indexes.map(&:name).join(', ')}"
1410
1645
  elsif matching_indexes.none?
1411
1646
  raise ArgumentError, "No indexes found on #{table_name} with the options provided."
1412
1647
  else
@@ -1414,11 +1649,11 @@ module ActiveRecord
1414
1649
  end
1415
1650
  end
1416
1651
 
1417
- def rename_table_indexes(table_name, new_name)
1652
+ def rename_table_indexes(table_name, new_name, **options)
1418
1653
  indexes(new_name).each do |index|
1419
- generated_index_name = index_name(table_name, column: index.columns)
1654
+ generated_index_name = index_name(table_name, column: index.columns, **options)
1420
1655
  if generated_index_name == index.name
1421
- rename_index new_name, generated_index_name, index_name(new_name, column: index.columns)
1656
+ rename_index new_name, generated_index_name, index_name(new_name, column: index.columns, **options)
1422
1657
  end
1423
1658
  end
1424
1659
  end
@@ -1436,10 +1671,6 @@ module ActiveRecord
1436
1671
  end
1437
1672
  end
1438
1673
 
1439
- def schema_creation
1440
- SchemaCreation.new(self)
1441
- end
1442
-
1443
1674
  def create_table_definition(name, **options)
1444
1675
  TableDefinition.new(self, name, **options)
1445
1676
  end
@@ -1448,8 +1679,12 @@ module ActiveRecord
1448
1679
  AlterTable.new create_table_definition(name)
1449
1680
  end
1450
1681
 
1451
- def extract_table_options!(options)
1452
- options.extract!(:temporary, :if_not_exists, :options, :as, :comment, :charset, :collation)
1682
+ def validate_create_table_options!(options)
1683
+ unless options[:_skip_validate_options]
1684
+ options
1685
+ .except(:_uses_legacy_table_name, :_skip_validate_options)
1686
+ .assert_valid_keys(valid_table_definition_options, valid_primary_key_options)
1687
+ end
1453
1688
  end
1454
1689
 
1455
1690
  def fetch_type_metadata(sql_type)
@@ -1464,7 +1699,7 @@ module ActiveRecord
1464
1699
  end
1465
1700
 
1466
1701
  def index_column_names(column_names)
1467
- if column_names.is_a?(String) && /\W/.match?(column_names)
1702
+ if expression_column_name?(column_names)
1468
1703
  column_names
1469
1704
  else
1470
1705
  Array(column_names)
@@ -1472,13 +1707,18 @@ module ActiveRecord
1472
1707
  end
1473
1708
 
1474
1709
  def index_name_options(column_names)
1475
- if column_names.is_a?(String) && /\W/.match?(column_names)
1710
+ if expression_column_name?(column_names)
1476
1711
  column_names = column_names.scan(/\w+/).join("_")
1477
1712
  end
1478
1713
 
1479
1714
  { column: column_names }
1480
1715
  end
1481
1716
 
1717
+ # Try to identify whether the given column name is an expression
1718
+ def expression_column_name?(column_name)
1719
+ column_name.is_a?(String) && /\W/.match?(column_name)
1720
+ end
1721
+
1482
1722
  def strip_table_name_prefix_and_suffix(table_name)
1483
1723
  prefix = Base.table_name_prefix
1484
1724
  suffix = Base.table_name_suffix
@@ -1487,15 +1727,16 @@ module ActiveRecord
1487
1727
 
1488
1728
  def foreign_key_name(table_name, options)
1489
1729
  options.fetch(:name) do
1490
- identifier = "#{table_name}_#{options.fetch(:column)}_fk"
1491
- hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
1730
+ columns = Array(options.fetch(:column)).map(&:to_s)
1731
+ identifier = "#{table_name}_#{columns * '_and_'}_fk"
1732
+ hashed_identifier = OpenSSL::Digest::SHA256.hexdigest(identifier).first(10)
1492
1733
 
1493
1734
  "fk_rails_#{hashed_identifier}"
1494
1735
  end
1495
1736
  end
1496
1737
 
1497
1738
  def foreign_key_for(from_table, **options)
1498
- return unless supports_foreign_keys?
1739
+ return unless use_foreign_keys?
1499
1740
  foreign_keys(from_table).detect { |fk| fk.defined_for?(**options) }
1500
1741
  end
1501
1742
 
@@ -1512,11 +1753,15 @@ module ActiveRecord
1512
1753
  end
1513
1754
  end
1514
1755
 
1756
+ def foreign_keys_enabled?
1757
+ @config.fetch(:foreign_keys, true)
1758
+ end
1759
+
1515
1760
  def check_constraint_name(table_name, **options)
1516
1761
  options.fetch(:name) do
1517
1762
  expression = options.fetch(:expression)
1518
1763
  identifier = "#{table_name}_#{expression}_chk"
1519
- hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
1764
+ hashed_identifier = OpenSSL::Digest::SHA256.hexdigest(identifier).first(10)
1520
1765
 
1521
1766
  "chk_rails_#{hashed_identifier}"
1522
1767
  end
@@ -1525,7 +1770,7 @@ module ActiveRecord
1525
1770
  def check_constraint_for(table_name, **options)
1526
1771
  return unless supports_check_constraints?
1527
1772
  chk_name = check_constraint_name(table_name, **options)
1528
- check_constraints(table_name).detect { |chk| chk.name == chk_name }
1773
+ check_constraints(table_name).detect { |chk| chk.defined_for?(name: chk_name, **options) }
1529
1774
  end
1530
1775
 
1531
1776
  def check_constraint_for!(table_name, expression: nil, **options)
@@ -1539,6 +1784,12 @@ module ActiveRecord
1539
1784
  end
1540
1785
  end
1541
1786
 
1787
+ def validate_table_length!(table_name)
1788
+ if table_name.length > table_name_length
1789
+ raise ArgumentError, "Table name '#{table_name}' is too long; the limit is #{table_name_length} characters"
1790
+ end
1791
+ end
1792
+
1542
1793
  def extract_new_default_value(default_or_changes)
1543
1794
  if default_or_changes.is_a?(Hash) && default_or_changes.has_key?(:from) && default_or_changes.has_key?(:to)
1544
1795
  default_or_changes[:to]
@@ -1552,29 +1803,8 @@ module ActiveRecord
1552
1803
  column_name.nil? && options.key?(:name) && options.except(:name, :algorithm).empty?
1553
1804
  end
1554
1805
 
1555
- def bulk_change_table(table_name, operations)
1556
- sql_fragments = []
1557
- non_combinable_operations = []
1558
-
1559
- operations.each do |command, args|
1560
- table, arguments = args.shift, args
1561
- method = :"#{command}_for_alter"
1562
-
1563
- if respond_to?(method, true)
1564
- sqls, procs = Array(send(method, table, *arguments)).partition { |v| v.is_a?(String) }
1565
- sql_fragments << sqls
1566
- non_combinable_operations.concat(procs)
1567
- else
1568
- execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
1569
- non_combinable_operations.each(&:call)
1570
- sql_fragments = []
1571
- non_combinable_operations = []
1572
- send(command, table, *arguments)
1573
- end
1574
- end
1575
-
1576
- execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
1577
- non_combinable_operations.each(&:call)
1806
+ def reference_name_for_table(table_name)
1807
+ table_name.to_s.singularize
1578
1808
  end
1579
1809
 
1580
1810
  def add_column_for_alter(table_name, column_name, type, **options)
@@ -1583,6 +1813,11 @@ module ActiveRecord
1583
1813
  schema_creation.accept(AddColumnDefinition.new(cd))
1584
1814
  end
1585
1815
 
1816
+ def change_column_default_for_alter(table_name, column_name, default_or_changes)
1817
+ cd = build_change_column_default_definition(table_name, column_name, default_or_changes)
1818
+ schema_creation.accept(cd)
1819
+ end
1820
+
1586
1821
  def rename_column_sql(table_name, column_name, new_column_name)
1587
1822
  "RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
1588
1823
  end
@@ -1613,12 +1848,12 @@ module ActiveRecord
1613
1848
  end
1614
1849
 
1615
1850
  def insert_versions_sql(versions)
1616
- sm_table = quote_table_name(schema_migration.table_name)
1851
+ sm_table = quote_table_name(pool.schema_migration.table_name)
1617
1852
 
1618
1853
  if versions.is_a?(Array)
1619
1854
  sql = +"INSERT INTO #{sm_table} (version) VALUES\n"
1620
- sql << versions.map { |v| "(#{quote(v)})" }.join(",\n")
1621
- sql << ";\n\n"
1855
+ sql << versions.reverse.map { |v| "(#{quote(v)})" }.join(",\n")
1856
+ sql << ";"
1622
1857
  sql
1623
1858
  else
1624
1859
  "INSERT INTO #{sm_table} (version) VALUES (#{quote(versions)});"