Detect long (BIGINT) arithmetic overflow instead of silently wrapping (#5164)#5604
Detect long (BIGINT) arithmetic overflow instead of silently wrapping (#5164)#5604ahkcs wants to merge 2 commits into
Conversation
PR Reviewer Guide 🔍(Review updated until commit 729438c)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to 729438c Explore these optional code suggestions:
Previous suggestionsSuggestions up to commit 729438c
Suggestions up to commit 1102cb2
Suggestions up to commit 8a628ff
Suggestions up to commit da07e56
Suggestions up to commit c35a804
|
7e0a74d to
2d2ef9f
Compare
|
Persistent review updated to latest commit 2d2ef9f |
2d2ef9f to
2d6e9a1
Compare
|
Persistent review updated to latest commit 2d6e9a1 |
2d6e9a1 to
fc2e0f2
Compare
|
Persistent review updated to latest commit fc2e0f2 |
fc2e0f2 to
447b958
Compare
|
Persistent review updated to latest commit 447b958 |
447b958 to
c35a804
Compare
|
Persistent review updated to latest commit c35a804 |
c35a804 to
da07e56
Compare
|
Persistent review updated to latest commit da07e56 |
da07e56 to
8a628ff
Compare
|
Persistent review updated to latest commit 8a628ff |
PPL/SQL long arithmetic (+, -, *) in eval/SELECT expressions silently wrapped on overflow in the Calcite engine (e.g. long_field * 999...9 wrapped to a negative value with HTTP 200). SqlStdOperatorTable.PLUS/MINUS/MULTIPLY generate plain Java +/-/* in the Enumerable code path, which wrap. Rewrite long +/-/* to their overflow-checked variants (CHECKED_PLUS / CHECKED_MINUS / CHECKED_MULTIPLY), which generate Math.addExact etc. and throw ArithmeticException on overflow. The exception is caught in QueryService and surfaced as a 4xx client error instead of wrapping or falling back to V2. Scoped to BIGINT operands only: narrower integer arithmetic (byte/short/int) is widened to a type that cannot overflow before this rewrite runs (PPLFuncImpTable promotes byte/short to INT and any int/long to BIGINT for +/-/*), so long — which has no wider integer type — is the sole remaining overflow case on the Calcite engine. Float/double/decimal follow IEEE 754 / decimal semantics and have no CHECKED_* runtime, so they are left untouched. The rewrite runs after the analytics-engine fork, so only the Calcite path is affected (the DataFusion backend handles its own overflow). The rewrite runs before pushdown so both coordinator-executed and pushed-down (script) arithmetic are checked; PPLAggregateConvertRule, OpenSearchRelOptUtil, and ExtendedRelJson recognize the CHECKED_* kinds so aggregate/sort pushdown and script serialization keep working. Adds a REST yaml test (issues/5164.yml) and updates the affected explain fixtures. Resolves opensearch-project#5164 Signed-off-by: Kai Huang <ahkcs@amazon.com>
8a628ff to
1102cb2
Compare
|
Persistent review updated to latest commit 1102cb2 |
| * Checked arithmetic is applied to BIGINT ({@code long}) operands only. Narrower integer | ||
| * arithmetic (byte/short/int) is already widened to a type that cannot overflow before this | ||
| * rewrite runs — {@code PPLFuncImpTable} promotes byte/short to INT and any int/long operand to | ||
| * BIGINT for {@code +}/{@code -}/{@code *} — so the sole remaining overflow case that reaches the | ||
| * Calcite engine is {@code long} arithmetic, which has no wider integer type to widen into. | ||
| * Float/double/decimal follow IEEE 754 (or decimal semantics) and have no {@code CHECKED_*} | ||
| * runtime (e.g. {@code SqlFunctions.checkedMultiply(double, double)} does not exist), so they are | ||
| * left untouched. Require both the result and every operand to be BIGINT. |
There was a problem hiding this comment.
simply comments. it duplicate with Line 431-434.
| QueryService.class); | ||
| } catch (Throwable t) { | ||
| if (isCalciteFallbackAllowed(t) && !(t instanceof NonFallbackCalciteException)) { | ||
| ArithmeticException overflow = findArithmeticOverflow(t); |
There was a problem hiding this comment.
Is there better way to handle expected calcite exception? can it wrapped with NonFallbackcalciteException?
There was a problem hiding this comment.
Good suggestion. I moved overflow handling to the Calcite execution boundary, where the wrapped ArithmeticException is translated into a top-level NonFallbackCalciteException. The outer catch now uses the existing generic fallback logic. Addressed in 729438c.
Signed-off-by: Kai Huang <ahkcs@amazon.com>
84fb906 to
729438c
Compare
|
Persistent review updated to latest commit 729438c |
1 similar comment
|
Persistent review updated to latest commit 729438c |
Description
long(BIGINT) arithmetic (+,-,*) in PPL/SQLeval/SELECTexpressions silently wrapped on overflow in the Calcite engine — e.g.long_field * 9999999999at the top of the 64-bit range returned a negative value with HTTP 200.SqlStdOperatorTable.PLUS/MINUS/MULTIPLYgenerate plain Java+/-/*in the Enumerable code path, which wrap.This rewrites
long+/-/*to their overflow-checked variants (CHECKED_PLUS/CHECKED_MINUS/CHECKED_MULTIPLY), which generateMath.addExact/subtractExact/multiplyExactand throwArithmeticExceptionon overflow. The exception is caught inQueryServiceand surfaced as a 4xx client error (NonFallbackCalciteException) instead of wrapping or falling back to the V2 engine. (The V2 engine already usesMath.*Exact.)Scope: BIGINT-only
The checked rewrite is gated to
long(BIGINT) operands. Narrower integer arithmetic (byte/short/int) is widened to a type that cannot overflow before this rewrite runs —PPLFuncImpTablepromotesbyte/short→intand anyint/longoperand →longfor+/-/*(#5603) — solong, which has no wider integer type to widen into, is the only remaining overflow case on the Calcite engine.float/double/decimalfollow IEEE 754 / decimal semantics and have noCHECKED_*runtime, so they are left untouched.The rewrite runs after the analytics-engine fork in
convertToCalcitePlan, so only the Calcite/Enumerable path is affected. The DataFusion analytics backend handles its ownlongoverflow (checked arrow kernels, opensearch-project/OpenSearch#22378) — the two engines now converge on erroring forlongoverflow.It runs before pushdown so both coordinator-executed and pushed-down (script) arithmetic are checked.
PPLAggregateConvertRule,OpenSearchRelOptUtil, andExtendedRelJsonrecognize theCHECKED_*kinds so aggregate-pushdown, sort-expression pushdown, and script serialization keep working for pushed-down checked arithmetic.Stacked on #5603
This PR is stacked on #5603 (operand widening) and depends on it: without the widening underneath,
short/intoverflow would slip through un-checked on the Calcite path. The first commit here is #5603's widening; it drops out of this diff once #5603 merges. Together the two PRs close integer-arithmetic overflow on the Calcite engine (#5603 widens the narrow tiers; this errors thelongtier), matching the analytics-engine behavior.Testing
issues/5164.yml(REST)int/shortoverflow → widened correct value (200);longoverflow (+/-/*) → 4xx; normal arithmetic unaffectedCalciteExplainIT(pushdown)CHECKED_*in pushed scriptsCalciteNoPushdownIT(CalciteExplainIT)Related Issues
Resolves #5164. Stacked on #5603. Analytics-engine counterpart: opensearch-project/OpenSearch#22378.
Check List
--signoffor-s.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.