Skip to content

Commit b68d53e

Browse files
authored
Added rename operation support (#146)
1 parent 7cd1388 commit b68d53e

File tree

2 files changed

+65
-8
lines changed

2 files changed

+65
-8
lines changed

mysql_ch_replicator/converter.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,13 @@ def convert_alter_query(self, mysql_query, db_name):
597597
if op_name == 'change':
598598
self.__convert_alter_table_change_column(db_name, table_name, tokens)
599599
continue
600+
601+
if op_name == 'rename':
602+
# Handle RENAME COLUMN operation
603+
if tokens[0].lower() == 'column':
604+
tokens = tokens[1:] # Skip the COLUMN keyword
605+
self.__convert_alter_table_rename_column(db_name, table_name, tokens)
606+
continue
600607

601608
raise Exception(f'operation {op_name} not implement, query: {subquery}, full query: {mysql_query}')
602609

@@ -808,6 +815,53 @@ def __convert_alter_table_change_column(self, db_name, table_name, tokens):
808815
query = f'ALTER TABLE `{db_name}`.`{table_name}` RENAME COLUMN {column_name} TO {new_column_name}'
809816
self.db_replicator.clickhouse_api.execute_command(query)
810817

818+
def __convert_alter_table_rename_column(self, db_name, table_name, tokens):
819+
"""
820+
Handle the RENAME COLUMN syntax of ALTER TABLE statements.
821+
Example: RENAME COLUMN old_name TO new_name
822+
"""
823+
if len(tokens) < 3:
824+
raise Exception('wrong tokens count for RENAME COLUMN', tokens)
825+
826+
# Extract old and new column names
827+
old_column_name = strip_sql_name(tokens[0])
828+
829+
# Check if the second token is "TO" (standard syntax)
830+
if tokens[1].lower() != 'to':
831+
raise Exception('expected TO keyword in RENAME COLUMN syntax', tokens)
832+
833+
new_column_name = strip_sql_name(tokens[2])
834+
835+
# Update table structure
836+
if self.db_replicator:
837+
if table_name in self.db_replicator.state.tables_structure:
838+
table_structure = self.db_replicator.state.tables_structure[table_name]
839+
mysql_table_structure: TableStructure = table_structure[0]
840+
ch_table_structure: TableStructure = table_structure[1]
841+
842+
# Update field name in MySQL structure
843+
mysql_field = mysql_table_structure.get_field(old_column_name)
844+
if mysql_field:
845+
mysql_field.name = new_column_name
846+
else:
847+
raise Exception(f'Column {old_column_name} not found in MySQL structure')
848+
849+
# Update field name in ClickHouse structure
850+
ch_field = ch_table_structure.get_field(old_column_name)
851+
if ch_field:
852+
ch_field.name = new_column_name
853+
else:
854+
raise Exception(f'Column {old_column_name} not found in ClickHouse structure')
855+
856+
# Preprocess to update primary key IDs if the renamed column is part of the primary key
857+
mysql_table_structure.preprocess()
858+
ch_table_structure.preprocess()
859+
860+
# Execute the RENAME COLUMN command in ClickHouse
861+
query = f'ALTER TABLE `{db_name}`.`{table_name}` RENAME COLUMN `{old_column_name}` TO `{new_column_name}`'
862+
if self.db_replicator:
863+
self.db_replicator.clickhouse_api.execute_command(query)
864+
811865
def _handle_create_table_like(self, create_statement, source_table_name, target_table_name, is_query_api=True):
812866
"""
813867
Helper method to handle CREATE TABLE LIKE statements.

test_mysql_ch_replicator.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,21 +2307,24 @@ def test_schema_evolution_with_db_mapping():
23072307

23082308
# Now follow user's sequence of operations with fully qualified names (excluding RENAME operation)
23092309
# 1. Add new column
2310-
mysql.execute(f"ALTER TABLE `{TEST_DB_NAME}`.`{TEST_TABLE_NAME}` ADD COLUMN added_new_column varchar(5)", commit=True)
2310+
mysql.execute(f"ALTER TABLE `{TEST_DB_NAME}`.`{TEST_TABLE_NAME}` ADD COLUMN added_new_column char(1)", commit=True)
23112311

2312-
# 2. Modify column type (skipping the rename step)
2313-
mysql.execute(f"ALTER TABLE `{TEST_DB_NAME}`.`{TEST_TABLE_NAME}` MODIFY added_new_column varchar(10)", commit=True)
2312+
# 2. Rename the column
2313+
mysql.execute(f"ALTER TABLE `{TEST_DB_NAME}`.`{TEST_TABLE_NAME}` RENAME COLUMN added_new_column TO rename_column_name", commit=True)
23142314

2315-
# 3. Insert data using the modified schema
2315+
# 3. Modify column type
2316+
mysql.execute(f"ALTER TABLE `{TEST_DB_NAME}`.`{TEST_TABLE_NAME}` MODIFY rename_column_name varchar(5)", commit=True)
2317+
2318+
# 4. Insert data using the modified schema
23162319
mysql.execute(
2317-
f"INSERT INTO `{TEST_DB_NAME}`.`{TEST_TABLE_NAME}` (id, name, added_new_column) VALUES (2, 'Second', 'ABCDE')",
2320+
f"INSERT INTO `{TEST_DB_NAME}`.`{TEST_TABLE_NAME}` (id, name, rename_column_name) VALUES (2, 'Second', 'ABCDE')",
23182321
commit=True,
23192322
)
23202323

2321-
# 4. Drop the column - this is where the error was reported
2322-
mysql.execute(f"ALTER TABLE `{TEST_DB_NAME}`.`{TEST_TABLE_NAME}` DROP COLUMN added_new_column", commit=True)
2324+
# 5. Drop the column - this is where the error was reported
2325+
mysql.execute(f"ALTER TABLE `{TEST_DB_NAME}`.`{TEST_TABLE_NAME}` DROP COLUMN rename_column_name", commit=True)
23232326

2324-
# 5. Add more inserts after schema changes to verify ongoing replication
2327+
# 6. Add more inserts after schema changes to verify ongoing replication
23252328
mysql.execute(
23262329
f"INSERT INTO `{TEST_DB_NAME}`.`{TEST_TABLE_NAME}` (id, name) VALUES (3, 'Third record after drop column')",
23272330
commit=True,

0 commit comments

Comments
 (0)