`avg` over a decimal with a negative scale panics with "attempt to divide by zero"
- Dominant language
- Rust
- Stars
- 9.3k
- Forks
- 2.4k
- Avg merge
- 3d 7h
- Merged PRs (30d)
- 344
Description
### Describe the bug
`DecimalAverager::try_new` (`datafusion/functions-aggregate-common/src/utils.rs`) computes `10^sum_scale` and `10^target_scale` with `pow_wrapping(scale as u32)`. For a negative scale the exponent wraps to a huge value and the wrapped power is 0. `DecimalAverager::avg` then evaluates `target_mul.div_wrapping(sum_mul)` with `sum_mul == 0` and panics.
All four decimal widths are affected (`Decimal32`, `Decimal64`, `Decimal128`, `Decimal256`); the plain aggregate, the grouped aggregate and `avg(DISTINCT ...)` all go through the same helper.
### To Reproduce
```sql
SELECT avg(x) FROM (VALUES (arrow_cast(1, 'Decimal128(10, -2)'))) t(x);
```
```text
thread 'main' panicked at library/core/src/num/mod.rs:475:5:
attempt to divide by zero
```
(`arrow_array::arithmetic::div_wrapping` called from `DecimalAverager::avg`, `datafusion/functions-aggregate-common/src/utils.rs`.)
### Expected behavior
`avg` of `100` and `200` at scale -2 (i.e. 10 000 and 20 000) returns `15000.00` as `Decimal128(14, 2)`, the type `Avg::return_type` already declares for that input.
### Additional context
The two factors are only ever used as the ratio `10^(target_scale - sum_scale)`, which is a plain non-negative exponent whenever the target scale is not smaller than the input scale (already enforced).
Found while running a corpus of extreme-value literals against a debug build of `datafusion-cli`.
Contributor guide
Research direction
Start in datafusion/functions-aggregate-common/src/utils.rs with DecimalAverager::try_new and DecimalAverager::avg, then reproduce the failure using the provided SQL query. Trace how negative scales produce the two power factors, and verify that decimal averages return the expected value without panicking for all four decimal widths and the plain, grouped, and DISTINCT aggregate paths.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, sql
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 84/100