@@ -50,49 +50,6 @@ fn format_database_change_error(table_name: &str, before_db: &str, after_db: &st
5050 )
5151}
5252
53- /// Generates a formatted error message for cluster field changes.
54- ///
55- /// This function creates a user-friendly error message explaining that cluster field
56- /// changes require manual intervention to prevent data loss. Cluster changes are even
57- /// more critical than database changes because they affect replication topology.
58- ///
59- /// # Arguments
60- /// * `table_name` - The name of the table being changed
61- /// * `before_cluster` - The original cluster name (or "<none>" if None)
62- /// * `after_cluster` - The new cluster name (or "<none>" if None)
63- ///
64- /// # Returns
65- /// A formatted string with migration instructions
66- fn format_cluster_change_error (
67- table_name : & str ,
68- before_cluster : & str ,
69- after_cluster : & str ,
70- ) -> String {
71- format ! (
72- "\n \n \
73- ERROR: Cluster field change detected for table '{}'\n \
74- \n \
75- The cluster field changed from '{}' to '{}'\n \
76- \n \
77- Changing the cluster field is a destructive operation that requires\n \
78- manual intervention to ensure data safety and proper replication.\n \
79- \n \
80- The cluster name is embedded in the table's replication path and cannot\n \
81- be changed without recreating the table. This would cause data loss.\n \
82- \n \
83- To migrate this table to a different cluster:\n \
84- \n \
85- 1. Export your existing data\n \
86- 2. Delete the old table definition from your code\n \
87- 3. Create a new table definition with the target cluster\n \
88- 4. Re-import your data if needed\n \
89- \n \
90- This ensures you maintain control over data migration and prevents\n \
91- accidental data loss.\n ",
92- table_name, before_cluster, after_cluster
93- )
94- }
95-
9653/// ClickHouse-specific table diff strategy
9754///
9855/// ClickHouse has several limitations that require drop+create operations instead of ALTER:
@@ -348,25 +305,15 @@ impl TableDiffStrategy for ClickHouseTableDiffStrategy {
348305 }
349306
350307 // Check if cluster has changed
351- // Cluster name cannot be changed after table creation for replicated tables
352- // as it's embedded in the replication path
353- let cluster_changed = before. cluster_name != after. cluster_name ;
354-
355- if cluster_changed {
356- let before_cluster = before. cluster_name . as_deref ( ) . unwrap_or ( "<none>" ) ;
357- let after_cluster = after. cluster_name . as_deref ( ) . unwrap_or ( "<none>" ) ;
358-
359- let error_message =
360- format_cluster_change_error ( & before. name , before_cluster, after_cluster) ;
361-
362- log:: error!( "{}" , error_message) ;
363-
364- return vec ! [ OlapChange :: Table ( TableChange :: ValidationError {
365- table_name: before. name. clone( ) ,
366- message: error_message,
367- before: Box :: new( before. clone( ) ) ,
368- after: Box :: new( after. clone( ) ) ,
369- } ) ] ;
308+ if before. cluster_name != after. cluster_name {
309+ log:: warn!(
310+ "ClickHouse: cluster changed for table '{}' (from {:?} to {:?}), requiring drop+create" ,
311+ before. name, before. cluster_name, after. cluster_name
312+ ) ;
313+ return vec ! [
314+ OlapChange :: Table ( TableChange :: Removed ( before. clone( ) ) ) ,
315+ OlapChange :: Table ( TableChange :: Added ( after. clone( ) ) ) ,
316+ ] ;
370317 }
371318
372319 // Check if PARTITION BY has changed
@@ -1337,27 +1284,16 @@ mod tests {
13371284
13381285 let changes = strategy. diff_table_update ( & before, & after, vec ! [ ] , order_by_change, "local" ) ;
13391286
1340- // Should return exactly one ValidationError
1341- assert_eq ! ( changes. len( ) , 1 ) ;
1287+ // Should return DROP + CREATE (like ORDER BY changes)
1288+ assert_eq ! ( changes. len( ) , 2 ) ;
13421289 assert ! ( matches!(
13431290 changes[ 0 ] ,
1344- OlapChange :: Table ( TableChange :: ValidationError { .. } )
1291+ OlapChange :: Table ( TableChange :: Removed ( _) )
1292+ ) ) ;
1293+ assert ! ( matches!(
1294+ changes[ 1 ] ,
1295+ OlapChange :: Table ( TableChange :: Added ( _) )
13451296 ) ) ;
1346-
1347- // Check the error message contains expected information
1348- if let OlapChange :: Table ( TableChange :: ValidationError {
1349- table_name,
1350- message,
1351- ..
1352- } ) = & changes[ 0 ]
1353- {
1354- assert_eq ! ( table_name, "test" ) ;
1355- assert ! ( message. contains( "<none>" ) ) ;
1356- assert ! ( message. contains( "test_cluster" ) ) ;
1357- assert ! ( message. contains( "manual intervention" ) ) ;
1358- } else {
1359- panic ! ( "Expected ValidationError variant" ) ;
1360- }
13611297 }
13621298
13631299 #[ test]
@@ -1378,27 +1314,16 @@ mod tests {
13781314
13791315 let changes = strategy. diff_table_update ( & before, & after, vec ! [ ] , order_by_change, "local" ) ;
13801316
1381- // Should return exactly one ValidationError
1382- assert_eq ! ( changes. len( ) , 1 ) ;
1317+ // Should return DROP + CREATE (like ORDER BY changes)
1318+ assert_eq ! ( changes. len( ) , 2 ) ;
13831319 assert ! ( matches!(
13841320 changes[ 0 ] ,
1385- OlapChange :: Table ( TableChange :: ValidationError { .. } )
1321+ OlapChange :: Table ( TableChange :: Removed ( _) )
1322+ ) ) ;
1323+ assert ! ( matches!(
1324+ changes[ 1 ] ,
1325+ OlapChange :: Table ( TableChange :: Added ( _) )
13861326 ) ) ;
1387-
1388- // Check the error message contains expected information
1389- if let OlapChange :: Table ( TableChange :: ValidationError {
1390- table_name,
1391- message,
1392- ..
1393- } ) = & changes[ 0 ]
1394- {
1395- assert_eq ! ( table_name, "test" ) ;
1396- assert ! ( message. contains( "test_cluster" ) ) ;
1397- assert ! ( message. contains( "<none>" ) ) ;
1398- assert ! ( message. contains( "manual intervention" ) ) ;
1399- } else {
1400- panic ! ( "Expected ValidationError variant" ) ;
1401- }
14021327 }
14031328
14041329 #[ test]
@@ -1419,27 +1344,16 @@ mod tests {
14191344
14201345 let changes = strategy. diff_table_update ( & before, & after, vec ! [ ] , order_by_change, "local" ) ;
14211346
1422- // Should return exactly one ValidationError
1423- assert_eq ! ( changes. len( ) , 1 ) ;
1347+ // Should return DROP + CREATE (like ORDER BY changes)
1348+ assert_eq ! ( changes. len( ) , 2 ) ;
14241349 assert ! ( matches!(
14251350 changes[ 0 ] ,
1426- OlapChange :: Table ( TableChange :: ValidationError { .. } )
1351+ OlapChange :: Table ( TableChange :: Removed ( _) )
1352+ ) ) ;
1353+ assert ! ( matches!(
1354+ changes[ 1 ] ,
1355+ OlapChange :: Table ( TableChange :: Added ( _) )
14271356 ) ) ;
1428-
1429- // Check the error message contains expected information
1430- if let OlapChange :: Table ( TableChange :: ValidationError {
1431- table_name,
1432- message,
1433- ..
1434- } ) = & changes[ 0 ]
1435- {
1436- assert_eq ! ( table_name, "test" ) ;
1437- assert ! ( message. contains( "cluster_a" ) ) ;
1438- assert ! ( message. contains( "cluster_b" ) ) ;
1439- assert ! ( message. contains( "replication path" ) ) ;
1440- } else {
1441- panic ! ( "Expected ValidationError variant" ) ;
1442- }
14431357 }
14441358
14451359 #[ test]
0 commit comments