fix: round large UInt64 values without narrowing#23033
Conversation
Signed-off-by: Kevin-Li-2025 <2242139@qq.com>
viirya
left a comment
There was a problem hiding this comment.
LGTM — this correctly fixes the narrowing path. A few notes from reviewing it:
The new round_unsigned_integer faithfully mirrors round_integer, and correctly omits the remainder <= -threshold branch since value % factor is always non-negative for u64 — that's a valid simplification, not a missing case. The HALF_UP tie-breaking, ANSI checked-overflow vs. non-ANSI wrapping, and the factor overflow → 0 short-circuit all match the signed version.
I verified the overflow test's expected value by hand: round(u64::MAX, -1, non-ansi) → remainder = (2^64-1) % 10 = 5, 5 >= 5 rounds up → wrapping_sub(5).wrapping_add(10) = 4, which is what the test asserts.
I ran both unit tests locally and they pass. (I couldn't run the SLT cases in my environment, but they exercise the same round_unsigned_integer paths the unit tests cover, and the expected values check out by hand.)
One optional nit: round_integer hoists let threshold = factor / 2; into a local and reuses it; the unsigned version inlines factor / 2 in the comparison. Matching the sibling function's style would read a bit more consistently — minor, take it or leave it.
|
Fyi we have an existing PR: This PR seems to fix only spark, while the original issue seems to describe for datafusion function. Also worth noting Spark doesn't support unsigned types in the first place (I made a comment to this affect on the linked PR) |
Which issue does this PR close?
Rationale for this change
Spark
roundcurrently narrowsUInt64inputs throughi64. Values abovei64::MAXtherefore fail even when a non-negative scale makes rounding a no-op. The narrowing also prevents correct negative-scale rounding for the upper half of theUInt64domain.What changes are included in this PR?
u64HALF_UP rounding path with the same ANSI overflow and non-ANSI wrapping behavior as the signed implementation.UInt64inputs.u64::MAXwith default/positive scales and a large negative-scale case.Are these changes tested?
Yes:
cargo test -p datafusion-spark function::math::round::tests --libcargo test -p datafusion-sqllogictest --test sqllogictests -- spark/math/round --test-threads 1cargo clippy -p datafusion-spark --features core --all-targets -- -D warningscargo fmt --all -- --checkAre there any user-facing changes?
Yes. Spark
roundnow acceptsUInt64values abovei64::MAXand returns correct results instead of reporting a narrowing error. There are no public API changes.