@@ -1391,18 +1391,80 @@ func (ch *ClickHouse) CheckReplicationInProgress(table metadata.TableMetadata) (
13911391 return true , nil
13921392}
13931393
1394+ // ColumnDataTypesWithTable extends ColumnDataTypes with database and table information for batch queries
1395+ type ColumnDataTypesWithTable struct {
1396+ Database string `ch:"database"`
1397+ Table string `ch:"table"`
1398+ Column string `ch:"column"`
1399+ Types []string `ch:"uniq_types"`
1400+ }
1401+
13941402// CheckSystemPartsColumns check data parts types consistency https://github.com/Altinity/clickhouse-backup/issues/529#issuecomment-1554460504
13951403func (ch * ClickHouse ) CheckSystemPartsColumns (ctx context.Context , table * Table ) error {
1396- var err error
1397- partColumnsDataTypes := make ([]ColumnDataTypes , 0 )
1398- partsColumnsSQL := "SELECT column, groupUniqArray(type) AS uniq_types " +
1404+ tables := []Table {* table }
1405+ return ch .CheckSystemPartsColumnsForTables (ctx , tables )
1406+ }
1407+
1408+ // CheckSystemPartsColumnsForTables checks data parts types consistency for multiple tables using a single SQL query
1409+ // This avoids having unfrozen data parts if only one table contains inconsistent column data types
1410+ func (ch * ClickHouse ) CheckSystemPartsColumnsForTables (ctx context.Context , tables []Table ) error {
1411+ if len (tables ) == 0 {
1412+ return nil
1413+ }
1414+
1415+ // Build the WHERE clause for all tables
1416+ var conditions []string
1417+ for _ , table := range tables {
1418+ if table .Skip {
1419+ continue
1420+ }
1421+ // Only check MergeTree family tables that have data
1422+ if ! strings .HasSuffix (table .Engine , "MergeTree" ) && table .Engine != "MaterializedMySQL" && table .Engine != "MaterializedPostgreSQL" {
1423+ continue
1424+ }
1425+ conditions = append (conditions , fmt .Sprintf ("(database='%s' AND table='%s')" , table .Database , table .Name ))
1426+ }
1427+
1428+ if len (conditions ) == 0 {
1429+ return nil
1430+ }
1431+
1432+ partColumnsDataTypes := make ([]ColumnDataTypesWithTable , 0 )
1433+ partsColumnsSQL := "SELECT database, table, column, groupUniqArray(type) AS uniq_types " +
13991434 "FROM system.parts_columns " +
1400- "WHERE active AND database=? AND table=? AND type NOT LIKE 'Enum%(%' AND type NOT LIKE 'Tuple(%' AND type NOT LIKE 'Nullable(Enum%(%' AND type NOT LIKE 'Nullable(Tuple(%' AND type NOT LIKE 'Array(Tuple(%' AND type NOT LIKE 'Nullable(Array(Tuple(%' " +
1401- "GROUP BY column HAVING length(uniq_types) > 1"
1402- if err = ch .SelectContext (ctx , & partColumnsDataTypes , partsColumnsSQL , table .Database , table .Name ); err != nil {
1435+ "WHERE active AND (" + strings .Join (conditions , " OR " ) + ") " +
1436+ "AND type NOT LIKE 'Enum%(%' AND type NOT LIKE 'Tuple(%' AND type NOT LIKE 'Nullable(Enum%(%' " +
1437+ "AND type NOT LIKE 'Nullable(Tuple(%' AND type NOT LIKE 'Array(Tuple(%' AND type NOT LIKE 'Nullable(Array(Tuple(%' " +
1438+ "GROUP BY database, table, column HAVING length(uniq_types) > 1"
1439+
1440+ if err := ch .SelectContext (ctx , & partColumnsDataTypes , partsColumnsSQL ); err != nil {
14031441 return err
14041442 }
1405- return ch .CheckTypesConsistency (table , partColumnsDataTypes )
1443+
1444+ // Group results by table and check consistency
1445+ tableDataTypes := make (map [string ][]ColumnDataTypes )
1446+ for _ , colData := range partColumnsDataTypes {
1447+ key := fmt .Sprintf ("%s.%s" , colData .Database , colData .Table )
1448+ tableDataTypes [key ] = append (tableDataTypes [key ], ColumnDataTypes {
1449+ Column : colData .Column ,
1450+ Types : colData .Types ,
1451+ })
1452+ }
1453+
1454+ // Check each table that has inconsistent types
1455+ for _ , table := range tables {
1456+ if table .Skip {
1457+ continue
1458+ }
1459+ key := fmt .Sprintf ("%s.%s" , table .Database , table .Name )
1460+ if colTypes , exists := tableDataTypes [key ]; exists {
1461+ if err := ch .CheckTypesConsistency (& table , colTypes ); err != nil {
1462+ return err
1463+ }
1464+ }
1465+ }
1466+
1467+ return nil
14061468}
14071469
14081470var dateWithParams = regexp .MustCompile (`^(Date[^(]+)\([^)]+\)` )
0 commit comments