fix: [bug] narrow BIGINT to INTEGER for int-domain function arguments (#5660) - #5728
fix: [bug] narrow BIGINT to INTEGER for int-domain function arguments (#5660)#5728AjimelecGonzalez wants to merge 1 commit into
Conversation
PR Reviewer Guide 🔍(Review updated until commit f1957a4)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to f1957a4 Explore these optional code suggestions:
Previous suggestionsSuggestions up to commit f6d8acb
Suggestions up to commit 0d3b11a
Suggestions up to commit c1295f6
|
c1295f6 to
0d3b11a
Compare
|
Persistent review updated to latest commit 0d3b11a |
dai-chen
left a comment
There was a problem hiding this comment.
High level question: the root cause is we widen arithmetic expressions to avoid overflow "unconditionally", can we list the options we've explored besides current PR approach?
|
FYI, in case it's useful — I did a quick check of how other databases handle integer arithmetic overflow. There are two independent decisions (partially done in #5603), and they explain our current implementation challenge in Calcite's combination. Option 1 — what type does
|
| Option | Engines | INT + INT |
consequence |
|---|---|---|---|
| Keep narrow | PostgreSQL, Calcite, Spark, Trino, DuckDB, SQL Server | INT |
overflow is possible at 32 bits, so Option 2 applies there |
| Widen one tier | MySQL, ClickHouse | BIGINT / Int64 |
overflow unreachable at 32 bits (int32×int32 = 2⁶² < 2⁶³); Option 2 applies at the 64-bit ceiling |
| One integer width | BigQuery (INT/SMALLINT/BIGINT are aliases for INT64) |
INT64 |
no narrow tier exists; Option 2 applies at 64 bits |
Note: widening only works because those engines' function libraries read every integer argument at 64 bits (MySQL
val_int()→longlong, ClickHousegetInt, BigQuery INT64-only, Trino@SqlType(INTEGER) long) — unlike Calcite, whoseleft/right/position/arrayItemOptional/sround/struncatetake primitiveintwith nolongoverload.
Option 2 — what happens when a value doesn't fit the type it was given?
| Option | Engines | observed |
|---|---|---|
| Throw | PostgreSQL, DuckDB, Trino, Spark-ANSI, SQL Server, BigQuery, MySQL | PG 2147483647+1 → ERROR 22003 integer out of range (int4pl) · DuckDB → Out of Range Error: Overflow in addition of INT32 · MySQL 9223372036854775807+1 → ERROR 1690 (22003) BIGINT value is out of range |
| No check — result wraps | Calcite default, Spark legacy, DataFusion, ClickHouse | Calcite 2147483647+1 → -2147483648 · ClickHouse toInt64(9223372036854775807)+1 → -9223372036854775808 |
| Per-call opt-out → NULL | BigQuery SAFE_ADD, Spark try_add, Trino/DuckDB TRY() |
explicit escape hatch layered over one of the above — never a default |
0d3b11a to
f6d8acb
Compare
|
Persistent review updated to latest commit f6d8acb |
As for the options explored: Options explored:
|
…opensearch-project#5660) PPL queries that pass integer arithmetic as an argument to functions requiring Java int parameters fail when Calcite is enabled: mvindex(arr, 1 + 1) -> CompileException: arrayItemOptional(List, long, ...) left('abcdef', 1 + 1) -> Unable to implement: SqlFunctions.left(String, long) round(123.456, 1 + 0) -> SqlFunctions.sround(BigDecimal, long) Root cause: PPL widens INTEGER arithmetic to BIGINT for overflow safety (opensearch-project#5603), so expressions like `1 + 1` produce BIGINT. Many Calcite runtime methods (ITEM, LEFT, RIGHT, ROUND, TRUNCATE, SUBSTRING, CONV, SHA2, etc.) take Java int parameters. Since SqlTypeFamily.INTEGER contains BIGINT, the call passes type checking but fails at code generation because the JVM cannot auto-narrow long to int. Fix: on operator resolution, narrow BIGINT args to INTEGER only at positions the operator's own type checker declares as a strict INTEGER family (derived from getParameterTypes(), not a hardcoded list). Value positions accepting a wider numeric type are never narrowed, so round(bigint_value, 2) keeps its BIGINT value. ARRAY_SLICE, TRUNCATE, and RAND gained explicit checkers so their INTEGER positions are visible. Overflow safety is preserved: arithmetic still computes in BIGINT; only the final value handed to an int-domain param is narrowed. Also fixes the pre-existing case of passing cast(x as long) to these functions. Issue: opensearch-project#5660 Signed-off-by: Ajimelec Gonzalez <ajimelec@amazon.com>
f6d8acb to
f1957a4
Compare
|
Persistent review updated to latest commit f1957a4 |
Description
PPL queries that pass integer arithmetic as an argument to functions requiring Java
intparameters fail when Calcite is enabled:Root cause: PPL widens
INTEGERarithmetic toBIGINTfor overflow safety (#5603), so expressions like1 + 1produceBIGINT. Many Calcite runtime methods (ITEM,LEFT,RIGHT,ROUND,TRUNCATE,SUBSTRING,CONV,SHA2,RAND, etc.) take Javaintparameters with nolongoverload. SinceSqlTypeFamily.INTEGERcontainsBIGINT, the call passes type checking but fails at code generation (EnumerableCalc) because the JVM cannot auto-narrowlongtoint.Fix:
BIGINTarguments back toINTEGERonly at operand positions that the operator's own registered type checker declares as a strictINTEGERfamily. The int-domain positions are derived from the type checker (getParameterTypes()), not a hardcoded per-function list, so new int-parameter functions are handled automatically as long as they register with a family/composite-family type checker.INTEGERis the sole numeric type accepted there. Value positions that also accept a wider numeric type are never narrowed — e.g.ROUND's first operand maps to theNUMERICfamily ([INTEGER, DOUBLE]), soround(bigint_value, 2)keeps itsBIGINTvalue operand and onlynarrows the precision.
INTEGERpositions are visible:ARRAY_SLICE,TRUNCATE, andRAND.Overflow safety is preserved: the arithmetic itself still computes in
BIGINT; only the final value handed to an int-domain parameter is narrowed. Arithmetic operators, comparisons,cast(x as long), aggregations, and long-field arithmetic are left untouched. The narrowing runs at plan time only, short-circuits when no argument isBIGINT, and degrades to a no-op (never fails the query) if an operator's type checker cannot be introspected.Also fixes the pre-existing case where an explicit
cast(x as long)is passed to these functions.Testing:
CalciteArrayFunctionIT,CalciteTextFunctionIT,CalciteMathematicalFunctionIT, andCalcitePPLBuiltinFunctionITcoveringmvindex,left,right,substring,round,truncate,conv,sha2, andrandwith arithmetic andcast(x as long)arguments, across local-execution, pushdown, aggregation, and sort/filter contexts.cast(x as long),max/sum, and long-field arithmetic still return the correctBIGINTtypes, and that the no-arg forms of the affected functions (e.g.rand(),truncate(x)) are unchanged.Related Issues
Resolves #5660
Related to #5603 (introduced the integer arithmetic widening that exposed this)
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.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.