hanke580 opened a new issue, #68123: URL: https://github.com/apache/doris/issues/68123
### Search before asking - [x] I had searched in the [issues](https://github.com/apache/doris/issues?q=is%3Aissue) and found no similar issues. ### Version Built from `master` at commit `c4dee4bd5e82c6f0f380e0243cbaf265999e6a6a` (2026-09-17). `./build.sh --fe --be`, single FE + single BE, default `fe.conf` and `be.conf`. Session defaults, unchanged: `check_overflow_for_decimal = 1`, `enable_decimal256 = 0`. ### What's Wrong? `SUM()` over a `DECIMAL` column returns a **silently wrong value** once the running total leaves the representable range. Doris already detects the very same overflow in binary arithmetic and refuses the query; the aggregate does not check at all. On two rows of `DECIMAL(38,0)` holding `10^38 - 1`: | expression | result | |---|---| | `a + a` | **errors** — `[E-255]Arithmetic overflow: 99999999999999999999999999999999999999 add 99999...` | | `a * 2` | **errors** — `[E-255]Arithmetic overflow: ... multiply 2 = 1999999...` | | **`SUM(a)`** | **`-14028236692093846346337460743176821145`** — no error | The same overflow, on the same two values, in the same query: refused in one expression and answered with a wrong number in the other. ### There are two distinct silent regimes, and the first one is the dangerous one With an ordinary 34-digit per-row value of `10^33`, summing *n* rows: | n | exact total | returned | | |---:|---|---|---| | 99 999 | 99999000000000000000000000000000000000 | same | ok | | **100 000** | 100000000000000000000000000000000000000 | **10000000000000000000000000000000000000** | **exactly one tenth — positive and plausible** | | 170 141 | 170141000000000000000000000000000000000 | **17014100000000000000000000000000000000** | one tenth | | **170 142** | 170142000000000000000000000000000000000 | **-17014036692093846346337460743176821145** | wrapped negative | | 199 998 | 199998000000000000000000000000000000000 | -14028436692093846346337460743176821145 | wrapped negative | The two boundaries are exactly the two representable limits involved: * **n = 100 000** is where the total first exceeds `DECIMAL(38,0)`'s maximum (`10^38 - 1`). From here the answer is the true total **divided by ten** — positive, 38 digits, entirely plausible, and wrong by an order of magnitude. * **n = 170 142** is where the total first exceeds `int128` max (`170141183460469231731687303715884105727`). From here it wraps negative. A negative sum of positive values is at least obviously broken. A result that is one tenth of the truth is not — nothing in the result, the type, or the log says anything is wrong. ### Every accumulation path is affected, including one that persists to disk Two rows of `DECIMAL(38,0)` holding `10^38 - 1`; exact total `199999999999999999999999999999999999998`: | path | returned | | |---|---|---| | `SUM(a)` | -14028236692093846346337460743176821145 | wrong | | `SUM(a) ... GROUP BY g` | -14028236692093846346337460743176821145 | wrong | | `SUM(a) OVER ()` | -14028236692093846346337460743176821145 | wrong | | `AVG(a)` | 8026480282232511287371606174911062.6544 | wrong | | **`AGGREGATE KEY` table, `a DECIMAL(38,0) SUM`** | -14028236692093846346337460743176821145 | **wrong, and stored on disk** | | `SUM(a) + 0` | errors | refuses | | `SUM(DISTINCT a)` | 99999999999999999999999999999999999999 | correct | Three things worth separating out: **`AVG` breaks an invariant that needs no arithmetic to check.** The average of two identical values is that value. Both inputs are `10^38 - 1`; the answer comes back as about `8.03 x 10^33`. `AVG` is dividing the already-wrapped total. **The `AGGREGATE KEY` case is not a query-time artifact.** That table pre-aggregates on write, so the wrapped value is what the storage engine persists. Two inserts of `10^38 - 1` leave the table holding a negative number and the inputs are gone. **`SUM(a) + 0` errors, and the error quotes the corrupted value:** ``` [E-255]Arithmetic overflow: -14028236692093846346337460743176821145 add 0 = DECIMAL128I ... ``` So the aggregate has already produced the wrapped number and handed it downstream; the only reason anything complains is that the *binary* operator is checked. This localises the gap precisely to the aggregate's own accumulation. ### `enable_decimal256 = true` fixes every case | `enable_decimal256` | 99 999 rows | 100 000 rows | 199 998 rows | |---|---|---|---| | `false` *(default)* | ok | **one tenth** | **negative** | | `true` | ok | ok | ok | ### What You Expected? Either the correct total, or an error. `check_overflow_for_decimal` is `1` by default and is documented as the switch that makes decimal overflow an error; it should cover the aggregate the same way it covers `a + a` and `a * 2`. Returning a positive, plausible number that is one tenth of the answer is the one outcome that should not happen. ### How to Reproduce? ```sql CREATE DATABASE IF NOT EXISTS ovf; -- 1. the contract, on two rows CREATE TABLE ovf.two (id INT, a DECIMAL(38,0)) DISTRIBUTED BY HASH(id) BUCKETS 1 PROPERTIES('replication_num'='1'); INSERT INTO ovf.two VALUES (1, 99999999999999999999999999999999999999), (2, 99999999999999999999999999999999999999); SELECT a + a FROM ovf.two LIMIT 1; -- E-255 Arithmetic overflow (correct) SELECT a * 2 FROM ovf.two LIMIT 1; -- E-255 Arithmetic overflow (correct) SELECT SUM(a) FROM ovf.two; -- -14028236692093846346337460743176821145 -- <-- no error -- 2. it is persisted by an AGGREGATE KEY table CREATE TABLE ovf.agg (k INT, a DECIMAL(38,0) SUM) AGGREGATE KEY(k) DISTRIBUTED BY HASH(k) BUCKETS 1 PROPERTIES('replication_num'='1'); INSERT INTO ovf.agg VALUES (1, 99999999999999999999999999999999999999); INSERT INTO ovf.agg VALUES (1, 99999999999999999999999999999999999999); SELECT a FROM ovf.agg; -- -14028236692093846346337460743176821145 -- 3. the two regimes, with an ordinary 34-digit value CREATE TABLE ovf.deep (id BIGINT, v DECIMAL(38,0)) DISTRIBUTED BY HASH(id) BUCKETS 1 PROPERTIES('replication_num'='1'); -- load 320000 rows of 10^33 (the script below does this by doubling) SELECT SUM(v) FROM (SELECT v FROM ovf.deep LIMIT 99999) x; -- correct SELECT SUM(v) FROM (SELECT v FROM ovf.deep LIMIT 100000) x; -- one tenth SELECT SUM(v) FROM (SELECT v FROM ovf.deep LIMIT 170142) x; -- negative SET enable_decimal256 = true; SELECT SUM(v) FROM (SELECT v FROM ovf.deep LIMIT 100000) x; -- correct ``` A self-contained script that builds the data and prints the tables above: ``` python3 repro.py --port 9030 # parts 1 and 2 of the report python3 verify-main.py --port 9030 # regime boundaries, all aggregate paths, AGGREGATE KEY ``` ### Anything Else? _No response_ ### Are you willing to submit PR? - [ ] Yes I am willing to submit a PR! ### Code of Conduct - [x] I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct) -- 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]
