Skip to content

Commit

Permalink
Fix renaming columns for tables with long names
Browse files Browse the repository at this point in the history
Fixes #59.
  • Loading branch information
fatkodima committed Aug 29, 2024
1 parent 2ed118d commit 766c552
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
31 changes: 24 additions & 7 deletions lib/online_migrations/schema_statements.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)}"
Expand All @@ -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
18 changes: 18 additions & 0 deletions test/schema_statements/renaming_columns_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down

0 comments on commit 766c552

Please sign in to comment.