andygrove opened a new issue, #6002:
URL: https://github.com/apache/datafusion-comet/issues/6002

   ### Describe the bug
   
   Comet's native decimal `SUM` validates the accumulator against the sum 
buffer's precision on **every update** and latches the failure. Spark does not 
check intermediate values at all in several common buffer layouts, so it can 
recover from a temporary overflow and return a result that fits.
   
   Where the two disagree, Comet returns `NULL` in legacy mode and raises 
`ARITHMETIC_OVERFLOW` under ANSI, while Spark returns a value. The aggregate 
runs entirely in Comet, so no mixed Comet/Spark plan is needed to hit this.
   
   ### Steps to reproduce
   
   One partition, no `GROUP BY`, whole-stage codegen enabled:
   
   ```sql
   CREATE TABLE t AS
     SELECT CAST(v AS DECIMAL(38,38)) AS v FROM VALUES ('0.6'), ('0.6'), 
('-0.6') AS s(v);
   
   SELECT SUM(v) FROM t;
   ```
   
   `DECIMAL(38,38)` matters because `Sum.resultType` is `DecimalType.bounded(p 
+ 10, s)`, which saturates at `(38, 38)` and leaves no headroom. The running 
sum reaches `1.2`, which does not fit in that precision, and the third value 
brings it back to `0.6`, which does.
   
   ### Expected behavior
   
   Spark returns `0.6` in both legacy and ANSI mode.
   
   Comet returns `NULL` in legacy mode and throws `ARITHMETIC_OVERFLOW` under 
ANSI.
   
   ### Additional context
   
   **Why Spark differs.** `Sum.add` uses `DecimalAddNoOverflowCheck` for 
decimal inputs. The doc comment on that expression says the overflow check is 
deliberately skipped because `UnsafeRowWriter` will perform it when the 
aggregation buffer is written. That only holds when the buffer actually is an 
`UnsafeRow`, and it is not in at least three places:
   
   - ungrouped `HashAggregateExec` under whole-stage codegen, which keeps the 
buffer in local `Decimal` variables (`doProduceWithoutKeys`),
   - window frames, where `AggregateProcessor` buffers into a 
`SpecificInternalRow`,
   - `ObjectHashAggregateExec`, which buffers the same way.
   
   In all three Spark keeps the wide intermediate and only `CheckOverflowInSum` 
at evaluate time decides. Grouped `HashAggregateExec` does write an 
`UnsafeRow`, so Spark nulls there too and Comet agrees.
   
   **Comet side.** `SumDecimalAccumulator::update_single` 
(`native/spark-expr/src/agg_funcs/sum_decimal.rs`, around line 202) and 
`SumDecimalGroupsAccumulator::update_single` (around line 421) both call 
`Decimal128Type::is_valid_decimal_precision` per row, then either set the sum 
to `None` permanently or raise immediately under ANSI. Once latched, a later 
cancelling value cannot recover the sum.
   
   **Scope.** This needs a decimal whose sum precision has little headroom, in 
practice an input precision of 28 or more, together with an intermediate that 
exceeds the buffer precision and later inputs that bring it back into range. 
`CometWindowExec` has no guard for the ever-expanding decimal `SUM` case either.
   
   **Related work.**
   
   - PR #5420 fixes exactly this class for decimal `AVG`, by keeping global and 
expanding-window decimal AVG in Spark once the sum precision reaches 
`DecimalType.MAX_PRECISION`. Decimal `SUM` has no equivalent guard in either 
the aggregate or the window path.
   - #5975 records the `0.6, 0.6, -0.6` behaviour, but as justification for an 
exclusion inside an enhancement about recovering native partial aggregate 
coverage. It does not track the wrong answer itself.
   - The measured control for the `DECIMAL(38,38)` case, run against a matching 
native library, is in 
https://github.com/apache/datafusion-comet/pull/5421#issuecomment-5504530845.
   - #4729 (closed) covered a different decimal SUM window overflow, where the 
result wrapped instead of returning NULL.
   
   **Suggested fix.** Either match Spark's deferred check by keeping an 
unbounded intermediate and validating once at `evaluate`, or add a precision 
guard mirroring the one in #5420, covering the ungrouped aggregate, the 
ever-expanding window frame, and `ObjectHashAggregate`.
   


-- 
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