Skip to content

[VL] Enable guarded decimal ROUND with cross-version coverage - #13103

Open
luis4a0 wants to merge 10 commits into
apache:mainfrom
luis4a0:feature/spark-round-delivery
Open

luis4a0 wants to merge 10 commits into
apache:mainfrom
luis4a0:feature/spark-round-delivery

Conversation

@luis4a0

@luis4a0 luis4a0 commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

What changes are proposed in this pull request?

Focused Gluten companion for facebookincubator/velox#19141,
following the compatibility review at
facebookincubator/velox#19141 (comment).

  • Preserve a typed NULL ROUND scale instead of serializing it as zero.
  • Accept foldable INTEGER decimal scales in [-400, 400] or NULL, including
    casts/arithmetic before Spark constant folding. The existing transformer
    emits typed literals for standard decimal_round execution.
  • Retain Spark execution outside the native supported scale interval instead
    of exposing its construction-time error, including when general native
    validation is disabled.
  • Add shared Spark-version compatibility tests and focused native validation
    tests. Integral/floating ROUND and scaled CEIL/FLOOR offload are unchanged.

Dependency: UPSTREAM_VELOX_PR_ID=19141 uses the existing developer hook
to exercise the upstream change in CI. This is a review/validation companion,
not a request to merge the temporary hook. Replace it with a qualified normal
Velox dependency containing the fix before merging.

How was this patch tested?

  • VeloxDecimalRoundSuite: typed-NULL serialization and scale guards.
  • SparkFunctionTest.decimalRoundScaleValidation, plus the existing native
    scalar-function regressions.
  • GlutenDecimalRoundSuite on Spark 3.4.4, 3.5.5, 4.0.2 and 4.1.1: actual
    Spark versus Gluten results and schemas, native-plan assertions, decimal
    storage transitions, 38-digit ties/carry/overflow, NULLs, folded scales and
    explicit fallback outside the checked interval. ConstantFolding-disabled
    coverage verifies that non-Literal foldable scales still offload safely.
  • The shared decimal suite is abstract in the backend-free common module;
    concrete version-specific suites are exercised through normal Maven
    wildcard discovery, with all four tests executed and no ignored tests.
  • JDK 17 for these profiles; Spark 4.1.1 also exercised on JDK 21.

Overflow remains an error in both ANSI modes. Spark's overflow diagnostic can
differ across versions/evaluation paths; exact diagnostic-text parity and
arbitrary Int32-scale JVM resource-limit behavior are not claimed.

October 27 refresh

Refreshed this branch by merging upstream main c5bd3de, preserving the reviewed history.

The bounded foldable-INTEGER/NULL eligibility and Spark fallback when native validation is disabled are unchanged. Rebuilt against main's public Velox dft-2026_10_26 pin with the current upstream decimal patch. The three native registration/validation tests, three JVM eligibility tests, and four Spark 4.1.1 SQL tests pass; the SQL suite passed on JDK 17 and 21. Explicit style checks also pass.

The temporary upstream-PR hook remains a development validation gate and is not waived for merge. These are local results for this refresh; fresh CI is still required, and earlier older-Spark results are not claimed as rerun on this merge.

Refresh commit: b3f7bb0

October 30 validation follow-up

Commit: bb36d43

Removed the duplicate decimal-specific Scala eligibility guard in response to:
#13103 (comment)

Normal compatibility policy now lives in the unified native Substrait validator. With native validation enabled, unsupported scales fall back to Spark. Disabling native validation is documented as a debug mode where unsupported native operations may fail at runtime instead of falling back.

Fresh local validation:

  • revised API and SQL tests failed before removing the Scala guard;
  • native ROUND validation/execution tests: 3 passed;
  • Velox validator API tests: 2 passed;
  • Spark 4.1 decimal integration tests: 4 passed on JDK 17 and JDK 21;
  • full Spark 4.1 reactor build, active Spotless/Scalastyle, license headers, and packaged native-library verification passed.

The native validator, decimal transformer format, supported [-400, 400] interval, typed-NULL behavior, and temporary dependency gate are unchanged. Fresh upstream CI and reviewer approval remain required.

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

Generated-by: GitHub Copilot CLI 1.0.91

Co-authored by Luis Penaranda and GitHub Copilot CLI 1.0.91.

@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

@github-actions github-actions Bot added CORE works for Gluten Core VELOX DOCS labels Sep 22, 2026
luis4a0 added a commit to luis4a0/velox that referenced this pull request Oct 5, 2026
## Summary
Implement standalone Spark-specific HALF_UP rounding for primitive numeric
and DECIMAL inputs. Correct floating decimal midpoints, integral overflow
behavior, negative scales, decimal result metadata, and NULL-scale handling.

## Prompting Intent
Provide a self-contained ROUND contribution directly on public main, without
unrelated numeric-function implementations or feature-branch prerequisites.
Preserve Spark 4.1 behavior within the explicit supported scale and JVM
domain, and keep unrelated Presto arithmetic unchanged.

## Linked Sources
- facebookincubator#10929
- https://github.com/apache/spark/blob/v4.1.1/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Double.html#toString(double)
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/math/RoundingMode.html#HALF_UP
- apache/gluten#13103

## Rationale
Compute HALF_UP rounding directly rather than reusing Presto's binary
multiply-and-round behavior. Use wide integer intermediates with explicit
LEGACY narrowing and captured ANSI mode, and validate decimal precision
before multiplication. Capability-specific integration aliases distinguish
the corrected implementation from older registrations and overlays.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
@luis4a0
luis4a0 force-pushed the feature/spark-round-delivery branch from 707345f to a2d95a6 Compare October 5, 2026 11:08
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Label: correctness

## Summary
Preserve typed NULL scales and validate decimal ROUND through the ordinary
native implementation. Enable negative decimal scales within [-400, 400]
and retain Spark fallback outside that interval. Add cross-version
integration coverage and use the existing upstream-PR developer hook.

## Prompting Intent
Address the compatibility review with a focused decimal Gluten companion,
using public Spark behavior and maintained native and SQL tests. Keep
integral, floating-point and scaled CEIL/FLOOR offload outside this change.

## Linked Sources
- facebookincubator/velox#19141
- facebookincubator/velox#19141 (comment)
- facebookincubator/velox#19141 (review)
- facebookincubator/velox#19469
- apache#13103

## Rationale
NULL is an execution value, not a zero rounding scale. Keep zero only for
resolved type calculation and preserve the typed NULL argument. Separate
frontend eligibility from the optional general native-validation switch
so unsupported scales always retain Spark execution.

Use the existing developer hook to validate Velox PR19141 in CI without
introducing capability aliases. Replace the temporary hook with a qualified
regular dependency before merging. Shared tests compare actual Spark and
Gluten results, schemas and execution placement on Spark 3.4 through 4.1,
while recognizing the releases' different decimal-overflow diagnostics.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
@luis4a0
luis4a0 force-pushed the feature/spark-round-delivery branch from a2d95a6 to d66fbf9 Compare October 14, 2026 09:10
@luis4a0 luis4a0 changed the title [VL] Enable Spark-correct ROUND through qualified native capabilities [VL] Enable guarded decimal ROUND with cross-version coverage Oct 14, 2026
@luis4a0
luis4a0 marked this pull request as ready for review October 14, 2026 09:11
Copilot AI balanced review requested due to automatic review settings October 14, 2026 09:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

3 open findings
What changed in this PR

Enables guarded native offload for decimal ROUND with support for NULL/negative scales and adds cross-Spark-version test coverage to validate results, schemas, and fallback behavior.

Changes:

  • Preserve typed-NULL ROUND scale in Substrait translation and validate decimal scale range [-400, 400] (or NULL) for native execution.
  • Add Spark/Gluten integration tests + Velox validator tests for decimal ROUND behavior across Spark 3.4–4.1.
  • Update docs to reflect partial support for round with decimal scale guarding and fallback.
File Description
gluten-ut/​spark41/​src/​test/​scala/​org/​apache/​gluten/​utils/​velox/​VeloxTestSettings.scala Enables the new shared GlutenDecimalRoundSuite for Spark 4.1 Velox backend tests.
gluten-ut/​spark40/​src/​test/​scala/​org/​apache/​gluten/​utils/​velox/​VeloxTestSettings.scala Enables the new shared GlutenDecimalRoundSuite for Spark 4.0 Velox backend tests.
gluten-ut/​spark35/​src/​test/​scala/​org/​apache/​gluten/​utils/​velox/​VeloxTestSettings.scala Enables the new shared GlutenDecimalRoundSuite for Spark 3.5 Velox backend tests.
gluten-ut/​spark34/​src/​test/​scala/​org/​apache/​gluten/​utils/​velox/​VeloxTestSettings.scala Enables the new shared GlutenDecimalRoundSuite for Spark 3.4 Velox backend tests.
gluten-ut/​common/​src/​test/​scala/​org/​apache/​spark/​sql/​GlutenDecimalRoundSuite.scala Adds cross-version Spark vs Gluten correctness/schema/native-plan tests for decimal ROUND.
gluten-substrait/​src/​main/​scala/​org/​apache/​gluten/​expression/​DecimalRoundTransformer.scala Preserves typed NULL scale when translating ROUND to Substrait (instead of serializing as 0).
ep/​build-velox/​src/​get-velox.sh Sets a hardcoded upstream Velox PR ID for builds.
docs/​velox-backend-scalar-function-support.md Documents partial support for round with decimal scales in [-400, 400] and NULL.
cpp/​velox/​tests/​SparkFunctionTest.cc Adds native validator test coverage for decimal ROUND scale acceptance/rejection.
cpp/​velox/​substrait/​SubstraitToVeloxPlanValidator.cc Implements native-side validation for decimal ROUND scale constraints and NULL scale.
backends-velox/​src/​test/​scala/​org/​apache/​gluten/​backendsapi/​velox/​VeloxDecimalRoundSuite.scala Adds Scala-side tests asserting typed-NULL serialization and validation behavior even when native validation is disabled.
backends-velox/​src/​main/​scala/​org/​apache/​gluten/​backendsapi/​velox/​VeloxValidatorApi.scala Adds JVM-side decimal ROUND scale validation to keep guards active when general native validation is disabled.

🧠 Review effort: Lite


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.


# Developer use only for testing Velox PR.
UPSTREAM_VELOX_PR_ID=""
UPSTREAM_VELOX_PR_ID="19141"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed that this must not become the normal merged dependency. This revision is intentionally a dependency-blocked validation companion: Rui explicitly requested exercising the upstream PR through the existing developer hook at facebookincubator/velox#19141 (comment) . Clearing the hook now would test the stock dependency without the decimal fix. The PR description records the merge gate: land the upstream fix, qualify a normal dependency containing it, then restore the empty hook before merging. Keeping this thread open to track that required dependency step.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@luis4a0 Yes, this is only for development testing, and we could remove this change after the corresponding Velox gets merged.

@luis4a0

luis4a0 commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

CI note for the current revision: the ARM cpp-test-udf-test job stops while
building Velox, before the unit-test step runs. GCC toolset 12 rejects the
selected -mcpu=neoverse-v3 target:
https://github.com/apache/gluten/actions/runs/38540379581/job/115774124930

The rounding changes do not modify architecture/compiler selection. This
needs alignment between the ARM runner target and compiler; I have not added
an architecture workaround to the rounding patch. Other checks are still
running.

Label: review-hardening

## Summary
Reuse typed arguments already prepared by scalar-function validation instead
of converting the decimal ROUND input a second time. Add regression coverage
for computed decimal inputs, including negative and NULL scales.

## Prompting Intent
Address the review's redundant-conversion concern consistently across the
ROUND companions without restricting valid computed child expressions.

## Linked Sources
- apache#13282 (comment)
- apache#13103

## Rationale
The scalar-function validator has already validated and converted every
argument before dispatching to the ROUND helper. Passing that existing
typed-expression vector follows the neighboring extract validator pattern
and preserves conversion/error handling while removing redundant work.
Checking the computed expression type retains support for casts rather than
restricting eligibility to direct field references.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
Copilot AI balanced review requested due to automatic review settings October 14, 2026 10:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

2 open findings
2 resolved since last review

🧠 Review effort: Lite

Comment thread ep/build-velox/src/get-velox.sh Resolved
@github-actions github-actions Bot added the BUILD label Oct 14, 2026
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Label: documentation

## Summary
Document independent JVM-side decimal ROUND eligibility and the aligned,
non-null typed-argument contract of the native ROUND validator.

## Prompting Intent
Address review comments consistently across the ROUND companions without
changing executable behavior or adding redundant fallback paths.

## Linked Sources
- apache#13282 (comment)
- apache#13282 (comment)
- apache#13103

## Rationale
The JVM guard is intentionally independent of optional native validation.
The private native helper receives one successfully converted expression per
Substrait argument; its caller exits or throws before dispatch on failure.
Document those responsibilities instead of suggesting native-only validation
or adding a silent fallback for an unreachable parameter state.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
Copilot AI balanced review requested due to automatic review settings October 15, 2026 10:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

4 open findings
1 resolved since last review

🧠 Review effort: Lite

Comment thread ep/build-velox/src/get-velox.sh Resolved
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

@rui-mo rui-mo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@luis4a0 Thanks. Please also note that there is a worflow failure.

org.apache.spark.sql.GlutenDecimalRoundSuite *** ABORTED ***
  java.lang.RuntimeException: Unable to load a Suite class org.apache.spark.sql.GlutenDecimalRoundSuite that was discovered in the runpath: null

* validation.
*/
override def doExprValidate(substraitExprName: String, expr: Expression): Boolean = expr match {
case round: Round if round.child.dataType.isInstanceOf[DecimalType] =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This validation might be duplicate, as we've added a native validation in the "SubstraitToVeloxPlanValidator.cc" (which is a preferred way with a unified validate API).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rui-mo, the bounds overlap, but these checks are not equivalent under the supported validation settings. spark.gluten.sql.enable.native.validation=false skips the JNI/Substrait plan validator. The Spark-expression eligibility hook still runs while constructing the candidate Substrait plan:

  • Mandatory expression eligibility:
    private def getAndCheckSubstraitName(
    expr: Expression,
    expressionsMap: Map[Class[_], String]): String = {
    TestStats.addExpressionClassName(expr.getClass.getName)
    // Check whether Gluten supports this expression
    expressionsMap
    .get(expr.getClass)
    .filter(BackendsApiManager.getValidatorApiInstance.doExprValidate(_, expr))
    .getOrElse {
    throw new GlutenNotSupportException(
    s"Not supported to map spark function name" +
    s" to substrait function name: $expr, class name: ${expr.getClass.getSimpleName}.")
    }
    }
  • Optional native plan validation:
    protected def doNativeValidation(context: SubstraitContext, node: RelNode): ValidationResult = {
    if (node != null && enableNativeValidation) {
    val planNode = PlanBuilder.makePlan(context, Lists.newArrayList(node))
    BackendsApiManager.getValidatorApiInstance
    .doNativeValidateWithFailureReason(planNode)
    } else {
    ValidationResult.succeeded
    }
    }

Without the JVM eligibility guard, that configuration could offload an unsupported scale and fail in native execution instead of retaining Spark. For example, Spark 4.1.1 successfully evaluates decimal ROUND at scales 401 and -401, while our documented native domain rejects them.

This uses the existing ValidatorApi.doExprValidate path, not an additional full validation pass. A rejected expression becomes a failed offload candidate through the normal validation/fallback path. I am retaining the guard to preserve this behavior independently of the optional native-validation flag.

GlutenDecimalRoundSuite explicitly exercises this configuration and checks both the fallback plan and Spark-compatible results:

testGluten(
"decimal ROUND retains NULL scales and guards extreme scales without native validation") {
withInput(DecimalType(3, 1), Seq("2.5", "-2.5", "0")) {
withSQLConf(
GlutenConfig.NATIVE_VALIDATION_ENABLED.key -> "false",
SQLConf.OPTIMIZER_EXCLUDED_RULES.key -> NullPropagation.ruleName) {
checkRound("CAST(NULL AS INT)")
checkRound("-401", native = false)
checkRound("401", native = false)
}
}
}
testGluten("decimal ROUND accepts foldable scales with constant folding disabled") {
withInput(DecimalType(3, 1), Seq("2.5", "-2.5", "0")) {
for (nativeValidation <- Seq("false", "true")) {
withSQLConf(
GlutenConfig.NATIVE_VALIDATION_ENABLED.key -> nativeValidation,
SQLConf.OPTIMIZER_EXCLUDED_RULES.key ->
s"${ConstantFolding.ruleName},${NullPropagation.ruleName}"
) {
val scales = sql("SELECT round(value, 1 - 2) FROM decimal_round_input")
.queryExecution.optimizedPlan.collect {
case node => node.expressions.flatMap(_.collect { case round: Round => round.scale })
}.flatten
assert(scales.nonEmpty)
assert(scales.forall(scale => scale.foldable && !scale.isInstanceOf[Literal]))
checkRound("1 - 2")
checkRound("-200 - 200")
checkRound("200 + 200")
checkRound("CAST(NULL AS INT)")
checkRound("400 + 1", native = false)
checkRound("-400 - 1", native = false)
}
}
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spark.gluten.sql.enable.native.validation = false

The intention is to perform native validation whenever possible, while avoiding introducing native-engine-specific logic into Scala. Instead, we aim to maintain a unified interface between Scala and native validation.

This configuration is primarily intended for debugging. It forces all computation to be offloaded to the native engine without fallback, meaning that unsupported operations will result in runtime exceptions rather than falling back to the original engine.

Does this approach make sense to you? Feel free to update the relevant documentation if anything is unclear.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rui-mo, agreed. I removed the decimal-specific doExprValidate policy from Scala and now rely on the existing native Substrait validator as the normal compatibility gate.

Commit: bb36d43

The behavior is now:

  • With native validation enabled (the default), scales outside [-400, 400] fail native validation and the expression falls back to Spark.
  • With native validation disabled for debugging, the plan remains native and the registered decimal special form reports its construction-time scale error at execution.

I also updated the internal configuration description to make that debug-mode behavior explicit.

The direct validator regression now verifies that Scala does not filter or eagerly evaluate invalid literals, nonliteral scales, foldable expressions, or an ANSI-true throwing cast. Integration tests cover normal fallback versus debug-mode native failure, while typed NULL and bounded foldable scales continue to execute natively.

Validation passed: native 3/3, API 2/2, Spark 4.1 SQL 4/4 on JDK 17 and 21, full Spark 4.1 reactor build, active Spotless/Scalastyle, license headers, and packaged native-library hash checks. Fresh upstream CI is still required.

## Summary
Keep the shared decimal ROUND checks in an abstract common suite and provide
concrete suite entry points in the Spark 3.4, 3.5, 4.0 and 4.1 test modules.
This prevents ScalaTest discovery from initializing backend settings while
running the backend-independent common module.

## Prompting Intent
Address the outstanding decimal ROUND review comments after checking which
requests were already implemented and answered. Fix the companion's public
CI verification blocker without changing rounding semantics or hiding tests.

## Linked Sources
- Review request: facebookincubator/velox#19141 (comment)
- Earlier compatibility response: facebookincubator/velox#19141 (comment)
- Gluten companion: apache#13103
- Spark 4.1 discovery failure: https://github.com/apache/gluten/actions/runs/38745047943/job/116463329992
- Spark 3.5 discovery failure: https://github.com/apache/gluten/actions/runs/38745047943/job/116463330043

## Rationale
The common module has no backend component registration. A concrete suite
there is discovered too early and aborts before the version-specific module
can run. Abstracting the shared suite preserves every test body, while the
small concrete subclasses keep the existing suite names and backend settings.
No workflow exclusion, disabled test, duplicated arithmetic or added backend
dependency is needed.

The original common-module discovery failure was reproduced. The same Maven
wildcard discovery now completes in common and executes all four decimal
checks in each qualified Spark module, with no ignored tests. Spark 4.1 was
also exercised on JDK 21.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
Copilot AI balanced review requested due to automatic review settings October 16, 2026 09:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return false;
}

const auto& valueType = params[0]->type();

# Developer use only for testing Velox PR.
UPSTREAM_VELOX_PR_ID=""
UPSTREAM_VELOX_PR_ID="19141"
Comment on lines +49 to +61
override def doExprValidate(substraitExprName: String, expr: Expression): Boolean = expr match {
case round: Round if round.child.dataType.isInstanceOf[DecimalType] =>
val scale = round.scale
val supported =
if (scale.dataType != IntegerType || !scale.foldable) {
false
} else {
scale.eval(EmptyRow) match {
case null => true
case value: Int => value >= -400 && value <= 400
case _ => false
}
}
import org.apache.spark.sql.internal.SQLConf
import org.apache.spark.sql.types._

import scala.collection.JavaConverters._
luis4a0 added a commit to luis4a0/velox that referenced this pull request Oct 16, 2026
## Summary
Support constant INTEGER scales in the inclusive range [-400, 400] for
decimal_round, decimal_ceil and decimal_floor. Reject other non-NULL scales
with an explicit user error during special-form construction, independently
of ANSI mode. Preserve NULL scales, unary ROUND's default scale and row-local
precision-overflow handling.

## Prompting Intent
Address the review request to document the decimal scale limitation and
reject unsupported native cases. Keep the change focused on the shared
decimal special forms and verify the boundaries through registered functions.

## Linked Sources
- Review request: facebookincubator#19141 (comment)
- Scale-domain discussion: facebookincubator#19141 (comment)
- Decimal correctness issue: facebookincubator#19469
- Guarded integration companion: apache/gluten#13103

## Rationale
Enforcing the supported domain in the shared constant-scale extractor keeps
ROUND, CEIL and FLOOR consistent and avoids returning unqualified mathematical
results for arbitrary INTEGER scales. This is a conservative native API
restriction, not an attempt to emulate JVM resource limits or a claim that
Spark rejects every scale outside the interval.

Construction-time errors are explicit even for zero/NULL input rows and
cannot be hidden by TRY. Row-local arithmetic overflow inside the supported
interval remains catchable. Checks run once during expression construction,
not per row.

The new rejection regression failed before the guard was added. Native tests
cover both decimal storage widths, both ANSI modes, direct/cast scales,
inclusive endpoints, their immediate neighbors and INTEGER extremes.
Maintained Gluten tests exercise supported scales and Spark fallback outside
the interval on the four qualified Spark versions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
## Summary
Clarify that decimal ROUND's inclusive [-400, 400] interval matches the
native supported domain. Gluten retains Spark execution outside it instead
of exposing the native unsupported-scale construction error.

## Prompting Intent
Keep the integration support documentation consistent with the native
decimal scale-validation follow-up requested during review.

## Linked Sources
- Native review request: facebookincubator/velox#19141 (comment)
- Native decimal change: facebookincubator/velox#19141
- Integration companion: apache#13103

## Rationale
The JVM/native eligibility guards already enforce the same interval, so no
integration behavior change is needed. The support table should distinguish
Spark fallback from direct native rejection and avoid implying that the
interval is only a test-selection convention.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
Copilot AI balanced review requested due to automatic review settings October 16, 2026 09:56
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

## Summary
Merge upstream main c5bd3de into the
decimal ROUND companion, preserving its bounded foldable-scale eligibility,
typed-NULL handling and native-validation-independent Spark fallback.

## Prompting Intent
Refresh the active OSS Gluten branches after addressing the upstream
decimal review. Preserve existing behavior and validate against the new
public native dependency selected by main.

## Linked Sources
- Companion: apache#13103
- Native dependency: facebookincubator/velox#19141
- Main: apache@c5bd3de

## Rationale
Keep both histories intact instead of rewriting previously reviewed commits.
Retain the relocated support documentation and all existing eligibility
checks while adopting main's public native pin.

The existing upstream-PR patch hook remains a development validation gate,
not a qualified production dependency or a waiver of its pre-merge removal.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
@luis4a0

luis4a0 commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Refreshed this branch by merging upstream main c5bd3de, preserving the reviewed history.

The bounded foldable-INTEGER/NULL eligibility and Spark fallback when native validation is disabled are unchanged. Rebuilt against main's public Velox dft-2026_10_26 pin with the current upstream decimal patch. The three native registration/validation tests, three JVM eligibility tests, and four Spark 4.1.1 SQL tests pass; the SQL suite passed on JDK 17 and 21. Explicit style checks also pass.

The temporary upstream-PR hook remains a development validation gate and is not waived for merge. These are local results for this refresh; fresh CI is still required, and earlier older-Spark results are not claimed as rerun on this merge.

Refresh commit: b3f7bb0

@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

luis4a0 added a commit to luis4a0/velox that referenced this pull request Oct 28, 2026
## Summary
Copy selected decimal values directly when both scale factors equal one, retaining result-type widening and NULL/selection handling. Add shared ROUND/CEIL/FLOOR identity coverage and keep public documentation focused on the supported contract.

## Prompting Intent
Address the latest reviewer feedback on the OSS decimal ROUND implementation, preserve Spark-compatible behavior and existing error contracts, and avoid unnecessary arithmetic on identity scales.

## Linked Sources
- Review: facebookincubator#19141 (review)
- Issue: facebookincubator#19469
- Validation companion: apache/gluten#13103

## Rationale
The shared factor predicate covers identity scales for all three policies. Validated result typing preserves the input scale and never reduces precision here, so a typed copy is sufficient; non-identity arithmetic and overflow handling stay unchanged. Encoding, lazy-input, precision-boundary, selection and result-reuse checks exercise the registered special forms. The related 52-test native suite passes. Documentation retains scale bounds, construction-time errors, and required Spark fallback without review-history rationale.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
@luis4a0

luis4a0 commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

I checked the remaining automated review concerns against the current source:

  • validateRound is private and called from validateScalarFunction, which constructs exactly one converted parameter per Substrait argument before dispatch. The existing argument-count check rejects fewer than two arguments before params[0] is accessed. There is no caller passing an independently sized parameter vector; the proposed size-mismatch scenario does not occur on this path.
  • Evaluating a foldable scale is intentional. Its evaluation errors must propagate rather than be swallowed during planning. The JVM regression explicitly checks an invalid foldable INTEGER cast, while other cases cover bounded foldable expressions and typed NULL with native validation disabled.
  • The validator deliberately combines the converted value type with the serialized scale literal: the former handles nontrivial input expressions; the latter checks the constant scale represented in the native plan.
  • The common test source still supports Scala 2.12 profiles, so its existing JavaConverters import is retained rather than replacing it with a Scala-2.13-only API.
  • The developer dependency hook remains an explicit merge gate, as already agreed in review. It will not be treated as merge-ready before a qualified normal Velox dependency includes the upstream change.

The companion's current CI is green, but the native PR now has a further reviewed identity-copy/documentation revision:
facebookincubator/velox@ef41496

Could a maintainer rerun this companion's CI against that updated native head after approving the Velox workflows? The existing green result qualified the previous native revision, not the new one. I cannot rerun upstream workflows with my current repository permissions.

@rui-mo

rui-mo commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

@luis4a0 Thanks for updating! Added one comment at #13103 (comment).

## Summary
Remove the duplicate decimal ROUND eligibility policy from the Velox Scala validator and rely on the existing unified native Substrait validator during normal planning. Document that disabling native validation is a debug mode that may surface unsupported-operation failures at runtime.

## Prompting Intent
Address Rui's review concern that backend-specific compatibility logic should not be duplicated in Scala and native code. Preserve normal Spark fallback through native validation while making the disabled-validation behavior explicit and tested.

## Linked Sources
- Review discussion: apache#13103 (comment)
- Native validator: https://github.com/apache/gluten/blob/b3f7bb0c11abb015c7980bf159ea93485737db2b/cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc
- Native implementation: facebookincubator/velox#19141

## Rationale
The native validator already owns decimal scale bounds and typed-NULL support, so the Scala guard duplicated backend policy and eagerly evaluated foldable expressions. In normal mode, native validation rejects unsupported scales and Gluten falls back to Spark. When validation is disabled for debugging, the plan remains native and the registered special form reports its construction-time scale error.

Red regressions demonstrated the old Scala guard intercepting invalid literal and foldable scales. Green coverage verifies backend-neutral expression eligibility, an ANSI-true throwing cast that is not eagerly evaluated, normal fallback, debug-mode native failures, typed NULL, foldable expressions, native validation, JDK 17/21, style, licensing, and packaged native libraries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

luis4a0 and others added 2 commits November 2, 2026 10:06
## Summary
Change the temporary upstream-PR dependency hook from GitHub's commit-series `.patch` endpoint to the final `.diff` endpoint for decimal ROUND qualification.

## Prompting Intent
Refresh the Gluten decimal companion against current main and the rebased Velox decimal PR while retaining the qualified IBM Velox pin and an explicit temporary dependency gate.

## Linked Sources
- Velox decimal PR: facebookincubator/velox#19141
- Gluten companion: apache#13103
- Architecture review: /root/lpenaranda_files/pr-reviews/round-refresh-20261102/round-refresh-review-2-gpt-6-astra.md

## Rationale
The rebased Velox PR retains eight logical commits, including historical intermediate integral changes that the later decimal-only split removes. Replaying that commit series cannot apply to IBM `dft-2026_10_30`, while the reviewed final decimal-only delta applies cleanly. The `.diff` endpoint transports that final delta without changing the pin or hiding the merge gate.

Both the currently published PR diff and the locally rebased final diff pass exact-pin apply checks. The resulting source matches the native/JVM tree validated by the refreshed native, API, Spark 4.1 JDK 17/21, packaging, style, and license suites.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
Copilot AI balanced review requested due to automatic review settings November 2, 2026 12:46
@luis4a0

luis4a0 commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

Refreshed this branch by merging current Gluten main e7d526abc3d9b6356fdff6954fa810bac9636810.

New head: 577df0a

Main advances the normal Velox base to IBM dft-2026_10_30. Native decimal PR #19141 is not merged, so the temporary dependency gate remains. Because the rebased PR retains historical intermediate commits that cannot replay on this older qualified pin, this branch now downloads GitHub's final PR .diff rather than the commit-series .patch. Both the published and rebased net deltas apply cleanly to the exact pin.

Fresh validation against that prepared dependency passed:

  • Native bridge tests: 3.
  • Validator API tests: 2.
  • Spark 4.1 SQL tests: 4 on JDK 17 and 4 on JDK 21.
  • Full Spark 4.1 reactor build, packaged native-library hash checks, Spotless/Scalastyle, and license headers.

The temporary hook remains a merge gate until a qualified normal Velox pin contains the decimal implementation.

luis4a0 added a commit to luis4a0/velox that referenced this pull request Nov 2, 2026
Implement standalone Spark-specific HALF_UP rounding for primitive numeric
and DECIMAL inputs. Correct floating decimal midpoints, integral overflow
behavior, negative scales, decimal result metadata, and NULL-scale handling.

Provide a self-contained ROUND contribution directly on public main, without
unrelated numeric-function implementations or feature-branch prerequisites.
Preserve Spark 4.1 behavior within the explicit supported scale and JVM
domain, and keep unrelated Presto arithmetic unchanged.

- facebookincubator#10929
- https://github.com/apache/spark/blob/v4.1.1/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Double.html#toString(double)
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/math/RoundingMode.html#HALF_UP
- apache/gluten#13103

Compute HALF_UP rounding directly rather than reusing Presto's binary
multiply-and-round behavior. Use wide integer intermediates with explicit
LEGACY narrowing and captured ANSI mode, and validate decimal precision
before multiplication. Capability-specific integration aliases distinguish
the corrected implementation from older registrations and overlays.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
luis4a0 added a commit to luis4a0/velox that referenced this pull request Nov 2, 2026
## Summary
Support constant INTEGER scales in the inclusive range [-400, 400] for
decimal_round, decimal_ceil and decimal_floor. Reject other non-NULL scales
with an explicit user error during special-form construction, independently
of ANSI mode. Preserve NULL scales, unary ROUND's default scale and row-local
precision-overflow handling.

## Prompting Intent
Address the review request to document the decimal scale limitation and
reject unsupported native cases. Keep the change focused on the shared
decimal special forms and verify the boundaries through registered functions.

## Linked Sources
- Review request: facebookincubator#19141 (comment)
- Scale-domain discussion: facebookincubator#19141 (comment)
- Decimal correctness issue: facebookincubator#19469
- Guarded integration companion: apache/gluten#13103

## Rationale
Enforcing the supported domain in the shared constant-scale extractor keeps
ROUND, CEIL and FLOOR consistent and avoids returning unqualified mathematical
results for arbitrary INTEGER scales. This is a conservative native API
restriction, not an attempt to emulate JVM resource limits or a claim that
Spark rejects every scale outside the interval.

Construction-time errors are explicit even for zero/NULL input rows and
cannot be hidden by TRY. Row-local arithmetic overflow inside the supported
interval remains catchable. Checks run once during expression construction,
not per row.

The new rejection regression failed before the guard was added. Native tests
cover both decimal storage widths, both ANSI modes, direct/cast scales,
inclusive endpoints, their immediate neighbors and INTEGER extremes.
Maintained Gluten tests exercise supported scales and Spark fallback outside
the interval on the four qualified Spark versions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
luis4a0 added a commit to luis4a0/velox that referenced this pull request Nov 2, 2026
## Summary
Copy selected decimal values directly when both scale factors equal one, retaining result-type widening and NULL/selection handling. Add shared ROUND/CEIL/FLOOR identity coverage and keep public documentation focused on the supported contract.

## Prompting Intent
Address the latest reviewer feedback on the OSS decimal ROUND implementation, preserve Spark-compatible behavior and existing error contracts, and avoid unnecessary arithmetic on identity scales.

## Linked Sources
- Review: facebookincubator#19141 (review)
- Issue: facebookincubator#19469
- Validation companion: apache/gluten#13103

## Rationale
The shared factor predicate covers identity scales for all three policies. Validated result typing preserves the input scale and never reduces precision here, so a typed copy is sufficient; non-identity arithmetic and overflow handling stay unchanged. Encoding, lazy-input, precision-boundary, selection and result-reuse checks exercise the registered special forms. The related 52-test native suite passes. Documentation retains scale bounds, construction-time errors, and required Spark fallback without review-history rationale.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d412b830-d346-4c14-b070-3bc5a6cacba1
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

This branch has not been deployed

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

Labels

BUILD CORE works for Gluten Core DOCS VELOX

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants