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 0d3b11a)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to 0d3b11a
Previous suggestionsSuggestions up to commit c1295f6
|
…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. The bug surfaces on: - Local execution: Calcite EnumerableCalc codegen -> Unable to implement Fix: - PPLFuncImpTable.resolve: for a known set of functions, narrow BIGINT arguments to INTEGER at the specific int-domain "control" positions (indices, lengths, precision, radix, bit-length, mode) via a per-function position map. Value/data positions are never narrowed, so e.g. round(bigint_value, 2) keeps its BIGINT first operand. 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. Also fixes the pre-existing case where an explicit cast(x as long) is passed to these functions. Issue: opensearch-project#5660 Signed-off-by: Ajimelec Gonzalez <[email protected]>
c1295f6 to
0d3b11a
Compare
|
Persistent review updated to latest commit 0d3b11a |
| * listed positions, never value/data positions (e.g. {@code ROUND}'s first operand may itself be | ||
| * a legitimate BIGINT to round, so only the precision at position 1 is narrowed). | ||
| */ | ||
| private static final java.util.Map<BuiltinFunctionName, int[]> INT_PARAM_POSITIONS = |
There was a problem hiding this comment.
This needs to maintain list of all function that can accept integer?
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 |
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 + 1produce BIGINT. Many Calcite runtime methods (ITEM,LEFT,RIGHT,ROUND,TRUNCATE,SUBSTRING,CONV,SHA2, etc.) take Javaintparameters. SinceSqlTypeFamily.INTEGERcontainsBIGINT, the call passes type checking but fails at code generation because the JVM cannot auto-narrowlongtoint.The bug surfaces on:
- Local execution: Calcite
EnumerableCalccodegen ->Unable to implementFix:
-
PPLFuncImpTable.resolve: for functions whose implementations requireint, narrowBIGINTarguments back toINTEGERat the plan layer.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.Also fixes the pre-existing case where an explicit
cast(x as long)is passed to these functions.Testing:
RelJsonSerializerTestcovering the serialization-layer type preservation.CalciteArrayFunctionIT,CalciteTextFunctionIT, andCalciteMathematicalFunctionITcoveringmvindex,left,right,substring,round,truncate,conv, andsha2witharithmetic and
cast(x as long)arguments.cast(x as long), and long-field arithmetic still return the correctBIGINTtypes.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.