matrixorigin / matrixorigin/matrixone

[Bug]: DECIMAL256 SUM persists values beyond its declared precision

Open
#28,866 1 comment 0 reactions 1 assignee Claimed by @slyunnn View on GitHub
kind/bug severity/s0
Dominant language
Go
Stars
1.9k
Forks
311
Avg merge
1d 3h
Merged PRs (30d)
768

Description

## Description

`SUM(DECIMAL(65,0))` can produce and persist a 66-digit value even though the expression and destination column are both declared `DECIMAL(65,0)`, MatrixOne's maximum public Decimal precision.

The declared precision is not enforced during aggregation, CTAS, or `INSERT ... SELECT`, so a column can contain a value outside its own SQL type domain.

## Environment

- MatrixOne: latest official `main`, commit `07fdd4ae0f80f287b93fc4b525fd296d5617abc7`
- Deployment: local standalone launch (isolated Log/TN/CN ports and data directory)

## Reproduction

```sql
create table src(d decimal(65,0));
insert into src values
(99999999999999999999999999999999999999999999999999999999999999999),
(1);

select cast(sum(d) as char), length(cast(sum(d) as char)) from src;

create table dst as select sum(d) s from src;
show create table dst;
select cast(s as char), length(cast(s as char)) from dst;

create table explicit_dst(s decimal(65,0));
insert into explicit_dst select sum(d) from src;
select cast(s as char), length(cast(s as char)) from explicit_dst;
```

## Actual behavior

All three paths return/store:

```text
100000000000000000000000000000000000000000000000000000000000000000
```

which contains 66 digits. `SHOW CREATE TABLE dst` still reports `s DECIMAL(65,0)`.

The negative mirror stores the 66-digit magnitude with a minus sign as well. Results reproduced identically in 3/3 fresh runs.

## Expected behavior

Because the exact result exceeds the declared maximum precision, the aggregate or assignment must return a Decimal out-of-range error. A `DECIMAL(65,0)` column must not persist a 66-digit magnitude.

## Controls

- signed/unsigned integer and `BIT(64)` SUM/AVG widen correctly and remain consistent across DOP 1/8 and resident/spill paths;
- valid in-range `DECIMAL(65,0)` sums remain exact;
- comparison confirms the returned sum is greater than the maximum legal `DECIMAL(65,0)` value, rather than a formatting artifact.

## Code-path analysis

`SumReturnType` in `pkg/sql/colexec/aggexec/sumavg2.go` declares every Decimal256 SUM as `DECIMAL(65, input_scale)`. Accumulation uses `Decimal256.Add256`, whose overflow check covers the physical 256-bit integer container, not the public 65-digit SQL precision. CTAS and assignment then preserve the out-of-domain payload without a width check.

## Related but distinct

- #28585 tracks failure to widen `DECIMAL(38)` SUM into Decimal256 for representable results.
- This report starts with an already-Decimal256 `DECIMAL(65)` input and concerns failure to enforce the maximum declared result precision.

## Suggested regression coverage

- positive and negative precision-65 overflow by one digit;
- ordinary/grouped/window/DISTINCT SUM, DOP 1/>1, partial/final, and spill;
- CTAS and `INSERT ... SELECT` into explicit Decimal destinations;
- near-boundary in-range controls.

## Duplicate search

Open and closed issues were searched for Decimal256 SUM overflow, `DECIMAL(65,0)`, 66-digit values, CTAS, and declared precision. Existing #28584/#28585 concern Decimal128 widening rather than this Decimal256 domain violation.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.