Describe the bug
DataTypeTests.testDynamicWithPrimitives (module client-v2, group integration) is flaky: it intermittently fails with
java.lang.ArithmeticException: Rounding necessary
at java.base/java.math.BigDecimal.divideAndRound(...)
at ...DataTypeTests.testDynamicWithPrimitives(DataTypeTests.java)
Observed in CI on the client-v2 + ClickHouse 25.8 matrix job (roughly ~1% of runs); passes on most runs and most server versions.
Root cause
The shared test fixture DataTypesTestingPOJO assigns its four Decimal fields from an unseeded Random:
decimal32 = BigDecimal.valueOf(random.nextDouble());
decimal64 = BigDecimal.valueOf(random.nextDouble());
decimal128 = BigDecimal.valueOf(random.nextDouble());
decimal256 = BigDecimal.valueOf(random.nextDouble());
testDynamicWithPrimitives inserts each value into a Dynamic column and, for the Decimal* cases, verifies the round-trip with
BigDecimal tmpDec = row.getBigDecimal("field").stripTrailingZeros();
if (tmpDec.divide((BigDecimal) value, RoundingMode.UNNECESSARY).equals(BigDecimal.ONE)) { continue; }
When a BigDecimal is written into a Dynamic column, the type is inferred from the value's precision() (SerializerUtils.valueToColumnForDynamicType): the width is chosen by precision, but the scale is forced to that width's maximum (Decimal32→9, Decimal64→18, Decimal128→38, Decimal256→76). A small-magnitude random.nextDouble() can produce a value whose scale() exceeds that fixed scale (e.g. 0.0123456789 → precision 9 → Decimal32(9), but scale 10 > 9). The value is then rounded on write, the read-back value no longer equals the original, and divide(value, RoundingMode.UNNECESSARY) throws Rounding necessary. Because the input is random, the failure is non-deterministic.
Expected behaviour
The test should be deterministic. Making the Decimal samples fixed values whose scale is within each inferred width's capacity keeps the round-trip exact and preserves the assertion's intent, while also letting the four samples genuinely exercise Decimal32/64/128/256 (the random doubles almost always landed in Decimal64).
Environment
- clickhouse-java:
main (client-v2)
- ClickHouse server: reproduced deterministically with a crafted small-scale value on current
main; originally observed on CI with server 25.8
Describe the bug
DataTypeTests.testDynamicWithPrimitives(moduleclient-v2, groupintegration) is flaky: it intermittently fails withObserved in CI on the
client-v2 + ClickHouse 25.8matrix job (roughly ~1% of runs); passes on most runs and most server versions.Root cause
The shared test fixture
DataTypesTestingPOJOassigns its fourDecimalfields from an unseededRandom:testDynamicWithPrimitivesinserts each value into aDynamiccolumn and, for theDecimal*cases, verifies the round-trip withWhen a
BigDecimalis written into aDynamiccolumn, the type is inferred from the value'sprecision()(SerializerUtils.valueToColumnForDynamicType): the width is chosen by precision, but the scale is forced to that width's maximum (Decimal32→9, Decimal64→18, Decimal128→38, Decimal256→76). A small-magnituderandom.nextDouble()can produce a value whosescale()exceeds that fixed scale (e.g.0.0123456789→ precision 9 →Decimal32(9), but scale 10 > 9). The value is then rounded on write, the read-back value no longer equals the original, anddivide(value, RoundingMode.UNNECESSARY)throwsRounding necessary. Because the input is random, the failure is non-deterministic.Expected behaviour
The test should be deterministic. Making the
Decimalsamples fixed values whose scale is within each inferred width's capacity keeps the round-trip exact and preserves the assertion's intent, while also letting the four samples genuinely exerciseDecimal32/64/128/256(the random doubles almost always landed inDecimal64).Environment
main(client-v2)main; originally observed on CI with server25.8