@@ -1657,3 +1657,158 @@ def test_enum_conversion():
16571657])
16581658def test_parse_db_name_from_query (query , expected ):
16591659 assert BinlogReplicator ._try_parse_db_name_from_query (query ) == expected
1660+
1661+
1662+ def test_create_table_like ():
1663+ """
1664+ Test that CREATE TABLE ... LIKE statements are handled correctly.
1665+ The test creates a source table, then creates another table using LIKE,
1666+ and verifies that both tables have the same structure in ClickHouse.
1667+ """
1668+ config_file = CONFIG_FILE
1669+ cfg = config .Settings ()
1670+ cfg .load (config_file )
1671+
1672+ mysql = mysql_api .MySQLApi (
1673+ database = None ,
1674+ mysql_settings = cfg .mysql ,
1675+ )
1676+
1677+ ch = clickhouse_api .ClickhouseApi (
1678+ database = TEST_DB_NAME ,
1679+ clickhouse_settings = cfg .clickhouse ,
1680+ )
1681+
1682+ prepare_env (cfg , mysql , ch )
1683+ mysql .set_database (TEST_DB_NAME )
1684+
1685+ # Create the source table with a complex structure
1686+ mysql .execute (f'''
1687+ CREATE TABLE `source_table` (
1688+ id INT NOT NULL AUTO_INCREMENT,
1689+ name VARCHAR(255) NOT NULL,
1690+ age INT UNSIGNED,
1691+ email VARCHAR(100) UNIQUE,
1692+ status ENUM('active','inactive','pending') DEFAULT 'active',
1693+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
1694+ data JSON,
1695+ PRIMARY KEY (id)
1696+ );
1697+ ''' )
1698+
1699+ # Get the CREATE statement for the source table
1700+ source_create = mysql .get_table_create_statement ('source_table' )
1701+
1702+ # Create a table using LIKE statement
1703+ mysql .execute (f'''
1704+ CREATE TABLE `derived_table` LIKE `source_table`;
1705+ ''' )
1706+
1707+ # Set up replication
1708+ binlog_replicator_runner = BinlogReplicatorRunner (cfg_file = config_file )
1709+ binlog_replicator_runner .run ()
1710+ db_replicator_runner = DbReplicatorRunner (TEST_DB_NAME , cfg_file = config_file )
1711+ db_replicator_runner .run ()
1712+
1713+ # Wait for database to be created and renamed from tmp to final
1714+ assert_wait (lambda : TEST_DB_NAME in ch .get_databases (), max_wait_time = 10.0 )
1715+
1716+ # Use the correct database explicitly
1717+ ch .execute_command (f'USE `{ TEST_DB_NAME } `' )
1718+
1719+ # Wait for tables to be created in ClickHouse with a longer timeout
1720+ assert_wait (lambda : 'source_table' in ch .get_tables (), max_wait_time = 10.0 )
1721+ assert_wait (lambda : 'derived_table' in ch .get_tables (), max_wait_time = 10.0 )
1722+
1723+ # Insert data into both tables to verify they work
1724+ mysql .
execute (
"INSERT INTO `source_table` (name, age, email, status) VALUES ('Alice', 30, '[email protected] ', 'active');" ,
commit = True )
1725+ mysql .
execute (
"INSERT INTO `derived_table` (name, age, email, status) VALUES ('Bob', 25, '[email protected] ', 'pending');" ,
commit = True )
1726+
1727+ # Wait for data to be replicated
1728+ assert_wait (lambda : len (ch .select ('source_table' )) == 1 , max_wait_time = 10.0 )
1729+ assert_wait (lambda : len (ch .select ('derived_table' )) == 1 , max_wait_time = 10.0 )
1730+
1731+ # Compare structures by reading descriptions in ClickHouse
1732+ source_desc = ch .execute_command ("DESCRIBE TABLE source_table" )
1733+ derived_desc = ch .execute_command ("DESCRIBE TABLE derived_table" )
1734+
1735+ # The structures should be identical
1736+ assert source_desc == derived_desc
1737+
1738+ # Verify the data in both tables
1739+ source_data = ch .select ('source_table' )[0 ]
1740+ derived_data = ch .select ('derived_table' )[0 ]
1741+
1742+ assert source_data ['name' ] == 'Alice'
1743+ assert derived_data ['name' ] == 'Bob'
1744+
1745+ # Both tables should have same column types
1746+ assert type (source_data ['id' ]) == type (derived_data ['id' ])
1747+ assert type (source_data ['name' ]) == type (derived_data ['name' ])
1748+ assert type (source_data ['age' ]) == type (derived_data ['age' ])
1749+
1750+ # Now test realtime replication by creating a new table after the initial replication
1751+ mysql .execute (f'''
1752+ CREATE TABLE `realtime_table` (
1753+ id INT NOT NULL AUTO_INCREMENT,
1754+ title VARCHAR(100) NOT NULL,
1755+ description TEXT,
1756+ price DECIMAL(10,2),
1757+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
1758+ PRIMARY KEY (id)
1759+ );
1760+ ''' )
1761+
1762+ # Wait for the new table to be created in ClickHouse
1763+ assert_wait (lambda : 'realtime_table' in ch .get_tables (), max_wait_time = 10.0 )
1764+
1765+ # Insert data into the new table
1766+ mysql .execute ("""
1767+ INSERT INTO `realtime_table` (title, description, price) VALUES
1768+ ('Product 1', 'First product description', 19.99),
1769+ ('Product 2', 'Second product description', 29.99),
1770+ ('Product 3', 'Third product description', 39.99);
1771+ """ , commit = True )
1772+
1773+ # Wait for data to be replicated
1774+ assert_wait (lambda : len (ch .select ('realtime_table' )) == 3 , max_wait_time = 10.0 )
1775+
1776+ # Verify the data in the realtime table
1777+ realtime_data = ch .select ('realtime_table' )
1778+ assert len (realtime_data ) == 3
1779+
1780+ # Verify specific values
1781+ products = sorted ([record ['title' ] for record in realtime_data ])
1782+ assert products == ['Product 1' , 'Product 2' , 'Product 3' ]
1783+
1784+ prices = sorted ([float (record ['price' ]) for record in realtime_data ])
1785+ assert prices == [19.99 , 29.99 , 39.99 ]
1786+
1787+ # Now create another table using LIKE after initial replication
1788+ mysql .execute (f'''
1789+ CREATE TABLE `realtime_like_table` LIKE `realtime_table`;
1790+ ''' )
1791+
1792+ # Wait for the new LIKE table to be created in ClickHouse
1793+ assert_wait (lambda : 'realtime_like_table' in ch .get_tables (), max_wait_time = 10.0 )
1794+
1795+ # Insert data into the new LIKE table
1796+ mysql .execute ("""
1797+ INSERT INTO `realtime_like_table` (title, description, price) VALUES
1798+ ('Service A', 'Premium service', 99.99),
1799+ ('Service B', 'Standard service', 49.99);
1800+ """ , commit = True )
1801+
1802+ # Wait for data to be replicated
1803+ assert_wait (lambda : len (ch .select ('realtime_like_table' )) == 2 , max_wait_time = 10.0 )
1804+
1805+ # Verify the data in the realtime LIKE table
1806+ like_data = ch .select ('realtime_like_table' )
1807+ assert len (like_data ) == 2
1808+
1809+ services = sorted ([record ['title' ] for record in like_data ])
1810+ assert services == ['Service A' , 'Service B' ]
1811+
1812+ # Clean up
1813+ db_replicator_runner .stop ()
1814+ binlog_replicator_runner .stop ()
0 commit comments