From 766c5527e7a774b85df67cfd96c62d3a5339d0cd Mon Sep 17 00:00:00 2001 From: fatkodima Date: Thu, 29 Aug 2024 23:23:29 +0300 Subject: [PATCH] Fix renaming columns for tables with long names Fixes #59. --- CHANGELOG.md | 2 ++ lib/online_migrations/schema_statements.rb | 31 ++++++++++++++----- .../renaming_columns_test.rb | 18 +++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a3b317..eb149d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## master (unreleased) +- Fix renaming columns for tables with long names + ## 0.19.3 (2024-08-09) - Fix idempotency for `add_index`/`remove_index` for expression indexes diff --git a/lib/online_migrations/schema_statements.rb b/lib/online_migrations/schema_statements.rb index 37fc2d1..06b9528 100644 --- a/lib/online_migrations/schema_statements.rb +++ b/lib/online_migrations/schema_statements.rb @@ -179,7 +179,7 @@ def initialize_column_rename(table_name, column_name, new_column_name) # def initialize_columns_rename(table_name, old_new_column_hash) transaction do - rename_table_create_view(table_name, old_new_column_hash) + __rename_table_and_create_view(table_name, old_new_column_hash) end end @@ -214,7 +214,9 @@ def revert_initialize_column_rename(table_name, column_name = nil, new_column_na def revert_initialize_columns_rename(table_name, _old_new_column_hash = nil) transaction do execute("DROP VIEW #{quote_table_name(table_name)}") - rename_table("#{table_name}_column_rename", table_name) + + tmp_table = __tmp_table_name_for_column_rename(table_name) + rename_table(tmp_table, table_name) end end @@ -241,7 +243,9 @@ def finalize_column_rename(table_name, column_name, new_column_name) def finalize_columns_rename(table_name, old_new_column_hash) transaction do execute("DROP VIEW #{quote_table_name(table_name)}") - rename_table("#{table_name}_column_rename", table_name) + + tmp_table = __tmp_table_name_for_column_rename(table_name) + rename_table(tmp_table, table_name) old_new_column_hash.each do |column_name, new_column_name| rename_column(table_name, column_name, new_column_name) end @@ -273,7 +277,7 @@ def revert_finalize_columns_rename(table_name, old_new_column_hash) old_new_column_hash.each do |column_name, new_column_name| rename_column(table_name, new_column_name, column_name) end - rename_table_create_view(table_name, old_new_column_hash) + __rename_table_and_create_view(table_name, old_new_column_hash) end end @@ -906,7 +910,8 @@ def pk_and_sequence_for(table) if renamed_tables.key?(table) super(renamed_tables[table]) elsif renamed_columns.key?(table) - super("#{table}_column_rename") + tmp_table = __tmp_table_name_for_column_rename(table) + super(tmp_table) else super end @@ -1046,8 +1051,9 @@ def __schema_for_table(table_name) schema ? quote(schema) : "current_schema()" end - def rename_table_create_view(table_name, old_new_column_hash) - tmp_table = "#{table_name}_column_rename" + def __rename_table_and_create_view(table_name, old_new_column_hash) + tmp_table = __tmp_table_name_for_column_rename(table_name) + rename_table(table_name, tmp_table) column_mapping = old_new_column_hash.map do |column_name, new_column_name| "#{quote_column_name(column_name)} AS #{quote_column_name(new_column_name)}" @@ -1059,5 +1065,16 @@ def rename_table_create_view(table_name, old_new_column_hash) FROM #{quote_table_name(tmp_table)} SQL end + + def __tmp_table_name_for_column_rename(table_name) + suffix = "_column_rename" + + # On ActiveRecord 7.1 can use table_name_length instead of max_identifier_length, + # see https://github.com/rails/rails/pull/45136. + # Also we need to account for "_pkey", because older versions does not correctly rename + # tables with long names. Remove when supporting newer versions only. + prefix_length = max_identifier_length - "_pkey".size - suffix.length + table_name[0, prefix_length] + suffix + end end end diff --git a/test/schema_statements/renaming_columns_test.rb b/test/schema_statements/renaming_columns_test.rb index 0e38ff7..b1f4639 100644 --- a/test/schema_statements/renaming_columns_test.rb +++ b/test/schema_statements/renaming_columns_test.rb @@ -204,6 +204,24 @@ def test_revert_finalize_columns_rename end end + def test_rename_column_in_table_with_long_name + # For ActiveRecord 7.1 use @connection.max_identifier_length, because older versions + # does not correctly generate pkey names when renaming, so need to use a shorter identifier. + table_name = "a" * 55 + @connection.create_table(table_name, force: true) do |t| + t.string :foo + end + + @connection.initialize_column_rename(table_name, :foo, :bar) + @connection.finalize_column_rename(table_name, :foo, :bar) + + column_names = @connection.columns(table_name).map(&:name) + + assert_equal ["id", "bar"], column_names + ensure + @connection.drop_table(table_name, if_exists: true) + end + # Test that it is properly reset in rails tests using fixtures. def test_initialize_column_rename_and_resetting_sequence column_renames("fname" => "first_name")