Shahzeb-DataEngineer opened a new pull request, #26652:
URL: https://github.com/apache/datafusion/pull/26652

   ## Which issue does this PR close?
   
   - Closes #26648
   
   ## Rationale for this change
   
   `sum()` over a DECIMAL column silently wraps on overflow and returns a wrong 
result. Summing two maximum `DECIMAL(38, 0)` values returns a negative number 
with 39 digits under a declared `Decimal128(38, 0)` result type:
   
   ```sql
   SELECT sum(v) FROM (VALUES
     (CAST('99999999999999999999999999999999999999' AS DECIMAL(38,0))),
     (CAST('99999999999999999999999999999999999999' AS DECIMAL(38,0)))) t(v);
   -- -140282366920938463463374607431768211458
   ```
   
   This is inconsistent with the rest of DataFusion: scalar decimal `+` and `*` 
raise an Arrow error on overflow, and `avg()` over the same data fails cleanly 
with "Arithmetic Overflow in AvgAccumulator". A silent wrong answer from an 
aggregate is worse than an error, so `sum()` should error the same way.
   
   Integer sums are intentionally unchanged: wrapping integer addition is 
DataFusion's documented lenient (non-ANSI) behavior. Only the decimal 
accumulator paths are affected.
   
   ## What changes are included in this PR?
   
   - `datafusion/functions-aggregate-common/src/utils.rs`: add 
`decimal_precision`, `add_decimal_checked` and `sub_decimal_checked` helpers. 
Decimal addition is checked against both the native type width and the declared 
precision (the bounded sum of two in-range decimals can exceed the declared 
precision without overflowing the native type, e.g. two `DECIMAL(38, 0)` maxima 
in an `i128`), and reports `Arithmetic Overflow in SumAccumulator`, mirroring 
the existing AvgAccumulator wording.
   - `datafusion/functions-aggregate/src/sum.rs`: `SumAccumulator` and 
`SlidingSumAccumulator` accumulate decimal inputs with the checked helpers in 
`update_batch`, `merge_batch` and `retract_batch` instead of the wrapping 
kernel sum. `Sum::groups_accumulator_supported` now returns false for decimal 
return types, because the primitive groups accumulator applies an infallible 
operation and cannot report overflow; decimal GROUP BY sums fall back to the 
fallible accumulator.
   - 
`datafusion/functions-aggregate-common/src/aggregate/sum_distinct/numeric.rs`: 
`DistinctSumAccumulator::evaluate` sums decimal values with the checked helper.
   
   ## What is the testing strategy for this PR?
   
   - New Rust unit tests: `decimal128_sum_overflow_errors`, 
`decimal128_sum_below_precision_limit_is_exact` and 
`decimal128_sliding_sum_overflow_errors` in `sum.rs`, and 
`decimal128_distinct_sum_overflow_errors` in `sum_distinct/numeric.rs`.
   - New sqllogictest cases at the end of 
`datafusion/sqllogictest/test_files/decimal.slt`: two-row Decimal128 overflow 
(plain, GROUP BY, and SUM(DISTINCT)), a Decimal256 overflow, and a 
large-but-valid sum that still computes exactly.
   - Ran: `cargo test -p datafusion-functions-aggregate sum`, `cargo test -p 
datafusion-functions-aggregate-common --lib`, and the `decimal` sqllogictests; 
all pass. `cargo fmt --all` and clippy on the touched crates are clean.
   
   ## Are there any user-facing changes?
   
   Yes: `sum()` over a DECIMAL now returns an `Arithmetic Overflow in 
SumAccumulator` execution error when the result does not fit in the result 
type, instead of returning a silently wrapped value. Non-overflowing decimal 
sums are unchanged, and integer sums keep their existing wrapping behavior.
   
   This PR was prepared with AI assistance; all changes and tests were reviewed 
and verified by me.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to