Skip to content

[GLUTEN-10134][Vl] elt ansi function overlay - #12873

Draft
zhouyuan wants to merge 3 commits into
apache:mainfrom
zhouyuan:vl-elt-ansi-function-overlay
Draft

[GLUTEN-10134][Vl] elt ansi function overlay#12873
zhouyuan wants to merge 3 commits into
apache:mainfrom
zhouyuan:vl-elt-ansi-function-overlay

Conversation

@zhouyuan

@zhouyuan zhouyuan commented Aug 24, 2026

Copy link
Copy Markdown
Member

What changes are proposed in this pull request?

fix ansi behavior section 4 in #10134

How was this patch tested?

Was this patch authored or co-authored using generative AI tooling?

zhouyuan and others added 3 commits August 24, 2026 11:19
Gluten has no per-function support for Spark's ANSI mode yet. Spark's elt
raises an error on an out-of-range index when ANSI mode is on and returns
NULL otherwise, and Velox has no elt at all, so the expression always falls
back today.

Implement elt in Gluten's function overlay instead of waiting for it to land
in Velox. It is a vector function covering both elt(integer, varchar...) and
elt(integer, varbinary...): a NULL index or a NULL selected input gives NULL,
NULLs in inputs that are not selected are ignored, and an index outside
[1, number of inputs] gives NULL with ANSI mode off and a user error with it
on. ANSI mode is read from SparkQueryConfig::ansiEnabled(), which Gluten
already populates from the session's spark.sql.ansi.enabled, the same channel
Velox's own sparksql functions use.

A vector function is used rather than a simple function because Velox's
SimpleFunctionAdapter has no VectorReader<Variadic<T>> constructor on the
initialize() path, so a variadic simple function cannot read the query config.
Rows are grouped by the input they select and each input is then copied in one
pass, which lets the result share the input's string buffers.

Spark captures the ANSI decision in Elt.failOnError at analysis time while
Velox derives it from the session config, so fall back when the two disagree,
which can happen if spark.sql.ansi.enabled changes between analysis and
execution.

Note that docs/velox-backend-scalar-function-support.md is generated by
tools/scripts/gen-function-support-docs.py from a test run and still lists elt
as unsupported; it needs a regeneration.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Velox's conv always lets the base conversion overflow, which its own comment
calls "consistent with Spark". That is only true with ANSI mode off: Spark's
NumberConverter.encode() saturates to 2^64 - 1 in that case, but raises
overflowInConvError when ANSI mode is on. conv is already reported as fully
supported, so an ANSI query silently gets the saturated value today.

Add an overlay override that keeps delegating the conversion to Velox's conv
and only adds the missing error. Before delegating, and only when ANSI mode is
on, it parses the digits the same way Velox does and raises a user error when
they do not fit in an unsigned 64-bit integer. That is exactly Spark's overflow
condition: the two checks in NumberConverter.encode() together detect that
accumulating the next digit would pass 2^64 - 1, which is what
std::from_chars reports as result_out_of_range.

Delegating rather than copying keeps the conversion logic, including its
handling of negative inputs and negative target bases, in one place, so the
overlay does not have to be kept in sync with fixes to Velox's conv. The sign
is applied after the digits are accumulated, so inputs like conv('-1', 10, 16)
still wrap around instead of raising an error, and an invalid base or an empty
input still gives NULL in ANSI mode.

As for elt, fall back when Conv.ansiEnabled, captured at analysis time,
disagrees with the session's spark.sql.ansi.enabled that Velox reads.

Note that Velox's conv only skips leading spaces while Spark trims the input
first, so an input led by another whitespace character, such as a tab, is
parsed as 0 by Velox. That is a pre-existing difference unrelated to ANSI mode
and is left alone here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…I-dependent legacySizeOfNull

element_at over an array raises an error for an index past either end of the
array when ANSI mode is on, and returns NULL otherwise. Velox's element_at is
Presto's SubscriptImpl with allowOutOfBound fixed to true, so it always returns
NULL. Add an overlay override that picks the instantiation matching the session's
ANSI mode.

The two remaining behaviors need no change and are kept: an index of 0 is an
error whatever the ANSI mode is, which Velox already reports as
"SQL array indices start at 1", and a key a map does not contain gives NULL,
because the map side of SubscriptImpl does not look at allowOutOfBound and
Spark's ElementAt does not pass failOnError to its map branch. GetMapValue,
which Gluten also lowers to element_at, has had no failOnError since Spark 3.4,
so it is unaffected too.

On the Scala side, fall back for an array input when ElementAt.failOnError
disagrees with the session's spark.sql.ansi.enabled, as for elt and conv, and
also when defaultValueOutOfBound is set, since Velox has no way to return a
default instead of NULL.

Size needs no code change: Spark's legacySizeOfNull is
'spark.sql.legacy.sizeOfNull AND NOT ANSI mode', evaluated at analysis time, and
ExpressionConverter already forwards Size.legacySizeOfNull to Velox's
size(collection, legacySizeOfNull) as a literal, so the ANSI-dependent value is
carried by the plan rather than re-derived natively. Add the tests that were
missing to lock that in, over both values of spark.sql.legacy.sizeOfNull and
both ANSI modes.

Note that GetArrayItem, the 0-based array[i] operator lowered to Velox's get, has
the same gap as element_at had: it throws invalidArrayIndexError under ANSI mode
for an out-of-bound or negative index, while Velox's get returns NULL. It needs
both allowOutOfBound and allowNegativeIndices flipped, and is left for a
follow-up.

The ANSI-on test suite added for elt is renamed to
ScalarFunctionsValidateSuiteAnsiOn, matching MathFunctionsValidateSuiteAnsiOn,
so it can host the ANSI counterparts of ScalarFunctionsValidateSuite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@zhouyuan zhouyuan changed the title Vl elt ansi function overlay [GLUTEN-10134][Vl] elt ansi function overlay Aug 24, 2026
@github-actions github-actions Bot added CORE works for Gluten Core VELOX DOCS labels Aug 24, 2026
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CORE works for Gluten Core DOCS VELOX

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant