Skip to content

Commit e81de4c

Browse files
committed
ClickHouse: triage smoke ClickHouse#9 new families — AggState float drift + Enum UPDATE
Two new reproducer families from smoke ClickHouse#9 triaged: 1. AggregateStateRoundtrip (3 reproducers): sum(c0) vs finalizeAggregation( arrayReduce('sumState', groupArray(c0))) returned different floats. Root cause is float-arithmetic non-associativity -- sum() over an unsorted table reads rows in storage order, sumState over a groupArray reads in array order; for floats, different orders produce different ULP-level sums. Not a CH bug. Restrict the oracle's sum branch to integer columns only. min/max/count are order-independent and safe on float. 2. SEMR (2) + AggregateStateRoundtrip (1): ALTER UPDATE assigning a numeric literal to an Enum column with CANNOT_CONVERT_TYPE. The mutation generator was type-blind. Filter target columns to plain primitives / Decimal / FixedString / DateTime64 -- skips Enum / composite / geo / JSON-family / AggregateFunction columns that can't accept arbitrary integer expressions.
1 parent 883a04e commit e81de4c

2 files changed

Lines changed: 32 additions & 3 deletions

File tree

src/sqlancer/clickhouse/gen/ClickHouseMutationGenerator.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,21 @@ public static SQLQueryAdapter getQuery(ClickHouseGlobalState state) {
5353
StringBuilder sb = new StringBuilder();
5454
switch (kind) {
5555
case ALTER_UPDATE:
56-
ClickHouseColumn updateCol = Randomly.fromList(cols);
56+
// Filter target columns to types where the existing expression generator produces
57+
// well-typed values. Enum / composite / geo / JSON-family rejects arbitrary integer
58+
// expressions with CANNOT_CONVERT_TYPE; aliased / materialised columns can't be
59+
// updated. Restrict to plain primitives.
60+
List<ClickHouseColumn> updatable = cols.stream().filter(c -> {
61+
sqlancer.clickhouse.ClickHouseType term = c.getType().getTypeTerm().unwrap();
62+
return term instanceof sqlancer.clickhouse.ClickHouseType.Primitive
63+
|| term instanceof sqlancer.clickhouse.ClickHouseType.Decimal
64+
|| term instanceof sqlancer.clickhouse.ClickHouseType.FixedString
65+
|| term instanceof sqlancer.clickhouse.ClickHouseType.DateTime64Type;
66+
}).collect(Collectors.toList());
67+
if (updatable.isEmpty()) {
68+
throw new IgnoreMeException();
69+
}
70+
ClickHouseColumn updateCol = Randomly.fromList(updatable);
5771
// Use an expression generator over the *other* columns so the assignment can't be a
5872
// pure recursive reference; this isn't strictly required by CH but keeps test variance
5973
// higher.

src/sqlancer/clickhouse/oracle/aggstate/ClickHouseAggregateStateRoundtripOracle.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,26 @@ public void check() throws SQLException {
5555
if (numericCols.isEmpty()) {
5656
throw new IgnoreMeException();
5757
}
58+
// For sum/avg, restrict to INTEGER columns -- float-arithmetic is non-associative, so
59+
// sum(unsorted_table) and sumState(groupArray(unsorted_table)) can return different
60+
// floats depending on read order. min/max/count are order-independent and safe on any
61+
// numeric type.
62+
String aggName = Randomly.fromOptions("min", "max", "count", "sum");
63+
if (aggName.equals("sum")) {
64+
List<ClickHouseColumn> intCols = numericCols.stream().filter(c -> {
65+
com.clickhouse.data.ClickHouseDataType t = c.getType().getType();
66+
return t != com.clickhouse.data.ClickHouseDataType.Float32
67+
&& t != com.clickhouse.data.ClickHouseDataType.Float64
68+
&& t != com.clickhouse.data.ClickHouseDataType.Decimal;
69+
}).collect(Collectors.toList());
70+
if (intCols.isEmpty()) {
71+
throw new IgnoreMeException();
72+
}
73+
numericCols = intCols;
74+
}
5875
ClickHouseColumn col = Randomly.fromList(numericCols);
5976
String fqTable = state.getDatabaseName() + "." + table.getName();
6077

61-
String aggName = Randomly.fromOptions("sum", "min", "max", "count");
62-
6378
String lhsQuery = "SELECT " + aggName + "(" + col.getName() + ") FROM " + fqTable;
6479
String rhsQuery = "SELECT finalizeAggregation(arrayReduce('" + aggName + "State', groupArray("
6580
+ col.getName() + "))) FROM " + fqTable;

0 commit comments

Comments
 (0)