@@ -1057,6 +1057,122 @@ def test_string_primary_key(monkeypatch):
10571057 binlog_replicator_runner .stop ()
10581058
10591059
1060+ def test_if_exists_if_not_exists (monkeypatch ):
1061+ monkeypatch .setattr (DbReplicator , 'INITIAL_REPLICATION_BATCH_SIZE' , 1 )
1062+
1063+ cfg = config .Settings ()
1064+ cfg .load (CONFIG_FILE )
1065+
1066+ mysql = mysql_api .MySQLApi (
1067+ database = None ,
1068+ mysql_settings = cfg .mysql ,
1069+ )
1070+
1071+ ch = clickhouse_api .ClickhouseApi (
1072+ database = TEST_DB_NAME ,
1073+ clickhouse_settings = cfg .clickhouse ,
1074+ )
1075+
1076+ prepare_env (cfg , mysql , ch )
1077+
1078+ binlog_replicator_runner = BinlogReplicatorRunner ()
1079+ binlog_replicator_runner .run ()
1080+ db_replicator_runner = DbReplicatorRunner (TEST_DB_NAME )
1081+ db_replicator_runner .run ()
1082+
1083+ assert_wait (lambda : TEST_DB_NAME in ch .get_databases ())
1084+
1085+ mysql .execute (f"CREATE TABLE IF NOT EXISTS { TEST_DB_NAME } .{ TEST_TABLE_NAME } (id int NOT NULL, PRIMARY KEY(id));" )
1086+ mysql .execute (f"CREATE TABLE IF NOT EXISTS { TEST_TABLE_NAME } (id int NOT NULL, PRIMARY KEY(id));" )
1087+ mysql .execute (f"CREATE TABLE IF NOT EXISTS { TEST_DB_NAME } .{ TEST_TABLE_NAME_2 } (id int NOT NULL, PRIMARY KEY(id));" )
1088+ mysql .execute (f"CREATE TABLE IF NOT EXISTS { TEST_TABLE_NAME_2 } (id int NOT NULL, PRIMARY KEY(id));" )
1089+ mysql .execute (f"DROP TABLE IF EXISTS { TEST_DB_NAME } .{ TEST_TABLE_NAME } ;" )
1090+ mysql .execute (f"DROP TABLE IF EXISTS { TEST_TABLE_NAME } ;" )
1091+
1092+ ch .execute_command (f'USE { TEST_DB_NAME } ' )
1093+
1094+ assert_wait (lambda : TEST_TABLE_NAME_2 in ch .get_tables ())
1095+ assert_wait (lambda : TEST_TABLE_NAME not in ch .get_tables ())
1096+
1097+ db_replicator_runner .stop ()
1098+ binlog_replicator_runner .stop ()
1099+
1100+
1101+ def test_percona_migration (monkeypatch ):
1102+ monkeypatch .setattr (DbReplicator , 'INITIAL_REPLICATION_BATCH_SIZE' , 1 )
1103+
1104+ cfg = config .Settings ()
1105+ cfg .load (CONFIG_FILE )
1106+
1107+ mysql = mysql_api .MySQLApi (
1108+ database = None ,
1109+ mysql_settings = cfg .mysql ,
1110+ )
1111+
1112+ ch = clickhouse_api .ClickhouseApi (
1113+ database = TEST_DB_NAME ,
1114+ clickhouse_settings = cfg .clickhouse ,
1115+ )
1116+
1117+ prepare_env (cfg , mysql , ch )
1118+
1119+ mysql .execute (f'''
1120+ CREATE TABLE { TEST_TABLE_NAME } (
1121+ `id` int NOT NULL,
1122+ PRIMARY KEY (`id`));
1123+ ''' )
1124+
1125+ mysql .execute (
1126+ f"INSERT INTO { TEST_TABLE_NAME } (id) VALUES (42)" ,
1127+ commit = True ,
1128+ )
1129+
1130+ binlog_replicator_runner = BinlogReplicatorRunner ()
1131+ binlog_replicator_runner .run ()
1132+ db_replicator_runner = DbReplicatorRunner (TEST_DB_NAME )
1133+ db_replicator_runner .run ()
1134+
1135+ assert_wait (lambda : TEST_DB_NAME in ch .get_databases ())
1136+
1137+ ch .execute_command (f'USE { TEST_DB_NAME } ' )
1138+
1139+ assert_wait (lambda : TEST_TABLE_NAME in ch .get_tables ())
1140+ assert_wait (lambda : len (ch .select (TEST_TABLE_NAME )) == 1 )
1141+
1142+ # Perform 'pt-online-schema-change' style migration to add a column
1143+ # This is a subset of what happens when the following command is run:
1144+ # pt-online-schema-change --alter "ADD COLUMN c1 INT" D=$TEST_DB_NAME,t=$TEST_TABLE_NAME,h=0.0.0.0,P=3306,u=root,p=admin --execute
1145+ mysql .execute (f'''
1146+ CREATE TABLE `{ TEST_DB_NAME } `.`_{ TEST_TABLE_NAME } _new` (
1147+ `id` int NOT NULL,
1148+ PRIMARY KEY (`id`)
1149+ )''' )
1150+
1151+ mysql .execute (
1152+ f"ALTER TABLE `{ TEST_DB_NAME } `.`_{ TEST_TABLE_NAME } _new` ADD COLUMN c1 INT;" )
1153+
1154+ mysql .execute (
1155+ f"INSERT LOW_PRIORITY IGNORE INTO `{ TEST_DB_NAME } `.`_{ TEST_TABLE_NAME } _new` (`id`) SELECT `id` FROM `{ TEST_DB_NAME } `.`{ TEST_TABLE_NAME } ` LOCK IN SHARE MODE;" ,
1156+ commit = True ,
1157+ )
1158+
1159+ mysql .execute (
1160+ f"RENAME TABLE `{ TEST_DB_NAME } `.`{ TEST_TABLE_NAME } ` TO `{ TEST_DB_NAME } `.`_{ TEST_TABLE_NAME } _old`, `{ TEST_DB_NAME } `.`_{ TEST_TABLE_NAME } _new` TO `{ TEST_DB_NAME } `.`{ TEST_TABLE_NAME } `;" )
1161+
1162+ mysql .execute (
1163+ f"DROP TABLE IF EXISTS `{ TEST_DB_NAME } `.`_{ TEST_TABLE_NAME } _old`;" )
1164+
1165+ mysql .execute (
1166+ f"INSERT INTO { TEST_TABLE_NAME } (id, c1) VALUES (43, 1)" ,
1167+ commit = True ,
1168+ )
1169+
1170+ assert_wait (lambda : len (ch .select (TEST_TABLE_NAME )) == 2 )
1171+
1172+ db_replicator_runner .stop ()
1173+ binlog_replicator_runner .stop ()
1174+
1175+
10601176def test_parse_mysql_table_structure ():
10611177 query = "CREATE TABLE IF NOT EXISTS user_preferences_portal (\n \t \t \t id char(36) NOT NULL,\n \t \t \t category varchar(50) DEFAULT NULL,\n \t \t \t deleted tinyint(1) DEFAULT 0,\n \t \t \t date_entered datetime DEFAULT NULL,\n \t \t \t date_modified datetime DEFAULT NULL,\n \t \t \t assigned_user_id char(36) DEFAULT NULL,\n \t \t \t contents longtext DEFAULT NULL\n \t \t ) ENGINE=InnoDB DEFAULT CHARSET=utf8"
10621178
@@ -1065,3 +1181,4 @@ def test_parse_mysql_table_structure():
10651181 structure = converter .parse_mysql_table_structure (query )
10661182
10671183 assert structure .table_name == 'user_preferences_portal'
1184+
0 commit comments