diff --git a/backends-velox/src/main/scala/org/apache/gluten/backendsapi/velox/VeloxValidatorApi.scala b/backends-velox/src/main/scala/org/apache/gluten/backendsapi/velox/VeloxValidatorApi.scala index e6f7a0fd92a..d4492ae7ed0 100644 --- a/backends-velox/src/main/scala/org/apache/gluten/backendsapi/velox/VeloxValidatorApi.scala +++ b/backends-velox/src/main/scala/org/apache/gluten/backendsapi/velox/VeloxValidatorApi.scala @@ -27,7 +27,7 @@ import org.apache.gluten.substrait.plan.PlanNode import org.apache.gluten.validate.NativePlanValidationInfo import org.apache.gluten.vectorized.NativePlanEvaluator -import org.apache.spark.sql.catalyst.expressions.{Attribute, Expression} +import org.apache.spark.sql.catalyst.expressions.Attribute import org.apache.spark.sql.catalyst.plans.physical.Partitioning import org.apache.spark.sql.execution.SparkPlan import org.apache.spark.sql.types._ @@ -41,10 +41,6 @@ import scala.collection.mutable.ArrayBuffer class VeloxValidatorApi extends ValidatorApi { import VeloxValidatorApi._ - /** For velox backend, key validation is on native side. */ - override def doExprValidate(substraitExprName: String, expr: Expression): Boolean = - true - override def doNativeValidateWithFailureReason(plan: PlanNode): ValidationResult = { TaskResources.runUnsafe { val validator = NativePlanEvaluator.create(BackendsApiManager.getBackendName) diff --git a/backends-velox/src/test/scala/org/apache/gluten/backendsapi/velox/VeloxDecimalRoundSuite.scala b/backends-velox/src/test/scala/org/apache/gluten/backendsapi/velox/VeloxDecimalRoundSuite.scala new file mode 100644 index 00000000000..8918a076695 --- /dev/null +++ b/backends-velox/src/test/scala/org/apache/gluten/backendsapi/velox/VeloxDecimalRoundSuite.scala @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.gluten.backendsapi.velox + +import org.apache.gluten.expression.{DecimalRoundTransformer, LiteralTransformer} +import org.apache.gluten.substrait.SubstraitContext + +import org.apache.spark.sql.catalyst.expressions.{Add, BoundReference, Cast, Literal, Round} +import org.apache.spark.sql.internal.SQLConf +import org.apache.spark.sql.types._ + +import org.scalatest.funsuite.AnyFunSuite + +class VeloxDecimalRoundSuite extends AnyFunSuite { + test("decimal round preserves a typed NULL scale") { + val value = Literal.create(Decimal(new java.math.BigDecimal("2.5")), DecimalType(3, 1)) + val scale = Literal.create(null, IntegerType) + val original = Round(value, scale) + val transformer = DecimalRoundTransformer("round", LiteralTransformer(value), original) + val scalar = transformer.doTransform(new SubstraitContext).toProtobuf.getScalarFunction + assert(scalar.getArgumentsCount == 2) + assert(scalar.getArguments(1).getValue.getLiteral.hasNull) + assert(transformer.dataType == DecimalType(3, 0)) + } + + test("decimal round eligibility defers to native validation") { + val validator = new VeloxValidatorApi + val value = BoundReference(0, DecimalType(38, 38), nullable = true) + val scales = Seq( + Literal(-401), + Literal(401), + BoundReference(1, IntegerType, nullable = false), + Add(Literal(400), Literal(1))) + scales.foreach { + scale => assert(validator.doExprValidate("round", Round(value, scale))) + } + val conf = new SQLConf + conf.setConfString(SQLConf.ANSI_ENABLED.key, "true") + SQLConf.withExistingConf(conf) { + val scale = Cast(Literal("invalid-scale"), IntegerType) + intercept[Exception](scale.eval()) + assert(validator.doExprValidate("round", Round(value, scale))) + } + } +} diff --git a/cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc b/cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc index 7ef0e807f1a..f64f67d373e 100644 --- a/cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc +++ b/cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc @@ -116,7 +116,7 @@ bool SubstraitToVeloxPlanValidator::flattenDualLevel(const TypePtr& type, std::v bool SubstraitToVeloxPlanValidator::validateRound( const ::substrait::Expression::ScalarFunction& scalarFunction, - const RowTypePtr& inputType) { + const std::vector& params) { const auto& arguments = scalarFunction.arguments(); if (arguments.size() < 2) { return false; @@ -127,6 +127,19 @@ bool SubstraitToVeloxPlanValidator::validateRound( return false; } + const auto& valueType = params[0]->type(); + if (valueType->isDecimal()) { + const auto& scale = arguments[1].value().literal(); + if (scale.has_null() && scale.null().has_i32()) { + return true; + } + if (scale.has_i32() && scale.i32() >= -400 && scale.i32() <= 400) { + return true; + } + LOG_VALIDATION_MSG("Decimal ROUND requires an INTEGER scale in [-400, 400] or NULL."); + return false; + } + // Velox has different result with Spark on negative scale. auto typeCase = arguments[1].value().literal().literal_type_case(); switch (typeCase) { @@ -213,7 +226,7 @@ bool SubstraitToVeloxPlanValidator::validateScalarFunction( std::vector types = SubstraitParser::getSubFunctionTypes(function); if (name == "round") { - return validateRound(scalarFunction, inputType); + return validateRound(scalarFunction, params); } if (name == "extract") { return validateExtractExpr(params); diff --git a/cpp/velox/substrait/SubstraitToVeloxPlanValidator.h b/cpp/velox/substrait/SubstraitToVeloxPlanValidator.h index cb8b322301f..6c2b8499369 100644 --- a/cpp/velox/substrait/SubstraitToVeloxPlanValidator.h +++ b/cpp/velox/substrait/SubstraitToVeloxPlanValidator.h @@ -149,8 +149,11 @@ class SubstraitToVeloxPlanValidator { /// Validate aggregate rel. bool validateAggRelFunctionType(const ::substrait::AggregateRel& substraitAgg); - /// Validate the round scalar function. - bool validateRound(const ::substrait::Expression::ScalarFunction& scalarFunction, const RowTypePtr& inputType); + /// Validate the round scalar function using its already-converted arguments. + /// The caller supplies one non-null expression for each Substrait argument. + bool validateRound( + const ::substrait::Expression::ScalarFunction& scalarFunction, + const std::vector& params); /// Validate extract function. bool validateExtractExpr(const std::vector& params); diff --git a/cpp/velox/tests/SparkFunctionTest.cc b/cpp/velox/tests/SparkFunctionTest.cc index 0384a69beee..4a97152e0f5 100644 --- a/cpp/velox/tests/SparkFunctionTest.cc +++ b/cpp/velox/tests/SparkFunctionTest.cc @@ -15,10 +15,13 @@ * limitations under the License. */ +#include +#include #include #include #include "operators/functions/RegistrationAllFunctions.h" +#include "substrait/SubstraitToVeloxPlanValidator.h" #include "velox/common/base/tests/GTestUtils.h" #include "velox/core/Expressions.h" #include "velox/functions/sparksql/SparkQueryConfig.h" @@ -125,6 +128,48 @@ TEST_F(SparkFunctionTest, roundWithDecimal) { runRoundWithDecimalTest(testRoundWithDecIntegralData()); } +TEST_F(SparkFunctionTest, decimalRoundScaleValidation) { + const auto validate = [&](std::optional scale, bool castInput) { + ::substrait::Expression expression; + auto* function = expression.mutable_scalar_function(); + function->set_function_reference(1); + auto* value = function->add_arguments()->mutable_value(); + if (castInput) { + auto* cast = value->mutable_cast(); + auto* type = cast->mutable_type()->mutable_decimal(); + type->set_precision(38); + type->set_scale(0); + type->set_nullability(::substrait::Type_Nullability_NULLABILITY_NULLABLE); + value = cast->mutable_input(); + } + value->mutable_selection()->mutable_direct_reference()->mutable_struct_field()->set_field(0); + auto* literal = function->add_arguments()->mutable_value()->mutable_literal(); + if (scale.has_value()) { + literal->set_i32(scale.value()); + } else { + literal->mutable_null()->mutable_i32()->set_nullability(::substrait::Type_Nullability_NULLABILITY_NULLABLE); + } + auto* output = function->mutable_output_type()->mutable_decimal(); + output->set_precision(38); + output->set_scale(0); + output->set_nullability(::substrait::Type_Nullability_NULLABILITY_NULLABLE); + gluten::SubstraitToVeloxPlanValidator validator(pool()); + return validator.validate( + expression, ROW({"value"}, {castInput ? VARCHAR() : DECIMAL(38, 0)}), {{1, "round:opt_dec<38,0>_i32"}}); + }; + for (const auto scale : {-400, -39, -38, -1, 0, 38, 400}) { + SCOPED_TRACE(scale); + EXPECT_TRUE(validate(scale, false)); + } + EXPECT_TRUE(validate(std::nullopt, false)); + EXPECT_TRUE(validate(-1, true)); + EXPECT_TRUE(validate(std::nullopt, true)); + for (const auto scale : {std::numeric_limits::min(), -401, 401, std::numeric_limits::max()}) { + SCOPED_TRACE(scale); + EXPECT_FALSE(validate(scale, false)); + } +} + TEST_F(SparkFunctionTest, expressionLevelAnsiCastIgnoresSessionAnsiOff) { queryCtx_->testingOverrideConfigUnsafe({{sparkAnsiEnabledConfigKey(), "false"}}); auto input = makeRowVector({makeFlatVector({"2147483648"})}); diff --git a/docs/backends/velox/velox-backend-scalar-function-support.md b/docs/backends/velox/velox-backend-scalar-function-support.md index 549c7f1b45b..2025e86ad09 100644 --- a/docs/backends/velox/velox-backend-scalar-function-support.md +++ b/docs/backends/velox/velox-backend-scalar-function-support.md @@ -297,7 +297,7 @@ The status applies to `spark.sql.ansi.enabled=false`. When ANSI mode is enabled, | randn | Randn | S | | | random | Rand | S | | | rint | Rint | S | | -| round | Round | S | | +| round | Round | PS | For decimal inputs, foldable INTEGER scales in the inclusive native-supported interval [-400, 400] and NULL are supported. Other decimal scales fall back to Spark instead of reaching the native unsupported-scale error. Integral and floating-point negative scales retain their existing fallback. | | sec | Sec | S | | | sign | Signum | S | | | signum | Signum | S | | @@ -538,4 +538,3 @@ The status applies to `spark.sql.ansi.enabled=false`. When ANSI mode is enabled, | xpath_number | XPathDouble | | | | xpath_short | XPathShort | | | | xpath_string | XPathString | | | - diff --git a/ep/build-velox/src/get-velox.sh b/ep/build-velox/src/get-velox.sh index 920909c8090..67ffbc1c0cc 100755 --- a/ep/build-velox/src/get-velox.sh +++ b/ep/build-velox/src/get-velox.sh @@ -25,7 +25,7 @@ RUN_SETUP_SCRIPT=ON ENABLE_ENHANCED_FEATURES=OFF # Developer use only for testing Velox PR. -UPSTREAM_VELOX_PR_ID="" +UPSTREAM_VELOX_PR_ID="19141" OS=`uname -s` @@ -140,10 +140,10 @@ function prepare_velox_source_code { function apply_provided_velox_patch { if [[ -n "$UPSTREAM_VELOX_PR_ID" ]]; then echo "Applying patch for PR #$UPSTREAM_VELOX_PR_ID ..." - local patch_name="$UPSTREAM_VELOX_PR_ID.patch" + local patch_name="$UPSTREAM_VELOX_PR_ID.diff" pushd $VELOX_HOME rm -f $patch_name - wget -nv "https://patch-diff.githubusercontent.com/raw/facebookincubator/velox/pull/$UPSTREAM_VELOX_PR_ID.patch" \ + wget -nv "https://patch-diff.githubusercontent.com/raw/facebookincubator/velox/pull/$UPSTREAM_VELOX_PR_ID.diff" \ -O "$patch_name" || { echo "Failed to download the Velox patch from GitHub" exit 1 diff --git a/gluten-substrait/src/main/scala/org/apache/gluten/config/GlutenConfig.scala b/gluten-substrait/src/main/scala/org/apache/gluten/config/GlutenConfig.scala index 70501f3256f..e0a7377e3ed 100644 --- a/gluten-substrait/src/main/scala/org/apache/gluten/config/GlutenConfig.scala +++ b/gluten-substrait/src/main/scala/org/apache/gluten/config/GlutenConfig.scala @@ -872,7 +872,8 @@ object GlutenConfig extends ConfigRegistry { .doc( "This is tmp config to specify whether to enable the native validation based on " + "Substrait plan. After the validations in all backends are correctly implemented, " + - "this config should be removed.") + "this config should be removed. Disabling native validation is intended for debugging " + + "and may cause unsupported operations to fail at runtime instead of falling back.") .booleanConf .createWithDefault(true) diff --git a/gluten-substrait/src/main/scala/org/apache/gluten/expression/DecimalRoundTransformer.scala b/gluten-substrait/src/main/scala/org/apache/gluten/expression/DecimalRoundTransformer.scala index a8ccd2635c1..e5cf7c1d7da 100644 --- a/gluten-substrait/src/main/scala/org/apache/gluten/expression/DecimalRoundTransformer.scala +++ b/gluten-substrait/src/main/scala/org/apache/gluten/expression/DecimalRoundTransformer.scala @@ -20,7 +20,7 @@ import org.apache.gluten.backendsapi.BackendsApiManager import org.apache.gluten.exception.GlutenNotSupportException import org.apache.spark.sql.catalyst.expressions._ -import org.apache.spark.sql.types.{DataType, DecimalType} +import org.apache.spark.sql.types.{DataType, DecimalType, IntegerType} case class DecimalRoundTransformer( substraitExprName: String, @@ -28,7 +28,8 @@ case class DecimalRoundTransformer( original: Round) extends BinaryExpressionTransformer { - val toScale: Int = original.scale.eval(EmptyRow).asInstanceOf[Int] + private val scaleValue = original.scale.eval(EmptyRow) + val toScale: Int = if (scaleValue == null) 0 else scaleValue.asInstanceOf[Int] // Use the same result type for different Spark versions in velox. // The same result type with spark in ch. @@ -43,5 +44,6 @@ case class DecimalRoundTransformer( } override def left: ExpressionTransformer = child - override def right: ExpressionTransformer = LiteralTransformer(toScale) + override def right: ExpressionTransformer = + LiteralTransformer(Literal.create(scaleValue, IntegerType)) } diff --git a/gluten-ut/common/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuiteBase.scala b/gluten-ut/common/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuiteBase.scala new file mode 100644 index 00000000000..ca3cd9b64a4 --- /dev/null +++ b/gluten-ut/common/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuiteBase.scala @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.spark.sql + +import org.apache.gluten.config.GlutenConfig +import org.apache.gluten.execution.ProjectExecTransformer + +import org.apache.spark.sql.catalyst.expressions.{Literal, Round} +import org.apache.spark.sql.catalyst.optimizer.{ConstantFolding, NullPropagation} +import org.apache.spark.sql.internal.SQLConf +import org.apache.spark.sql.types._ + +import scala.collection.JavaConverters._ + +abstract class GlutenDecimalRoundSuiteBase extends GlutenSQLTestsTrait { + private def withInput(dataType: DecimalType, values: Seq[String])(f: => Unit): Unit = { + val schema = new StructType().add("value", dataType) + val rows = values.map(value => Row(new java.math.BigDecimal(value))) :+ Row(null) + withSQLConf( + SQLConf.ADAPTIVE_EXECUTION_ENABLED.key -> "false", + GlutenConfig.GLUTEN_ANSI_FALLBACK_ENABLED.key -> "false") { + withTempPath { + path => + spark.createDataFrame(rows.asJava, schema).coalesce(1).write.parquet(path.toString) + withTempView("decimal_round_input") { + spark.read.parquet(path.toString).createOrReplaceTempView("decimal_round_input") + f + } + } + } + } + + private def assertExecution(df: DataFrame, native: Boolean): Unit = { + val plan = df.queryExecution.executedPlan + val locations = plan.collect { + case node if node.expressions.exists(_.exists(_.isInstanceOf[Round])) => + node.isInstanceOf[ProjectExecTransformer] + } + assert( + locations.nonEmpty && locations.forall(_ == native), + s"Unexpected ROUND execution:\n$plan") + } + + private def checkRound(scale: String, native: Boolean = true): Unit = { + val query = s"SELECT round(value, $scale) FROM decimal_round_input" + withSQLConf(GlutenConfig.GLUTEN_ENABLED.key -> "false") { + val vanilla = sql(query) + val expectedSchema = vanilla.schema + val expected = vanilla.collect().toSeq + withSQLConf(GlutenConfig.GLUTEN_ENABLED.key -> "true") { + val df = sql(query) + assertExecution(df, native) + assert(df.schema == expectedSchema) + checkAnswer(df, expected) + } + } + } + + testGluten("decimal ROUND preserves schemas and HALF_UP results across storage boundaries") { + val cases = Seq( + (DecimalType(3, 1), Seq("2.5", "-2.5", "0")), + (DecimalType(18, 0), Seq("999999999999999999", "-999999999999999999")), + (DecimalType(19, 0), Seq("9999999999999999999", "-9999999999999999999")), + (DecimalType(38, 1), Seq("9" * 37 + ".9", "-" + "9" * 37 + ".9")), + (DecimalType(38, 38), Seq("0.6", "-0.6", "0.5", "-0.5")) + ) + for ((dataType, values) <- cases) { + withInput(dataType, values) { + for (ansi <- Seq("false", "true")) { + withSQLConf(SQLConf.ANSI_ENABLED.key -> ansi) { + Seq(-400, -39, -1, 0, 1, 38, 400).foreach(scale => checkRound(scale.toString)) + checkRound("-1 + 0") + } + } + } + } + } + + testGluten("decimal ROUND handles the 38-digit HALF_UP tie and precision overflow") { + withInput(DecimalType(38, 0), Seq("4" + "9" * 37, "-4" + "9" * 37)) { + checkRound("-38") + } + for ((value, scale) <- Seq(("9" * 38, -1), ("5" + "0" * 37, -38), ("-5" + "0" * 37, -38))) { + withInput(DecimalType(38, 0), Seq(value)) { + for (ansi <- Seq("false", "true")) { + withSQLConf(SQLConf.ANSI_ENABLED.key -> ansi) { + val query = s"SELECT round(value, $scale) FROM decimal_round_input" + withSQLConf(GlutenConfig.GLUTEN_ENABLED.key -> "false") { + val error = intercept[Exception](sql(query).collect()) + assert(Iterator.iterate[Throwable](error)(_.getCause).takeWhile(_ != null).exists { + cause => + Option(cause.getMessage).exists { + message => + message.contains("NUMERIC_VALUE_OUT_OF_RANGE") || + message.contains("DECIMAL_PRECISION_EXCEEDS_MAX_PRECISION") + } + }) + } + val df = sql(query) + assertExecution(df, native = true) + val error = intercept[Exception](df.collect()) + assert(Iterator.iterate[Throwable](error)(_.getCause).takeWhile(_ != null).exists { + cause => Option(cause.getMessage).exists(_.contains("Decimal overflow")) + }) + } + } + } + } + } + + testGluten("decimal ROUND debug mode bypasses compatibility fallback") { + 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") + checkRound("401") + } + } + } + + 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)") + if (nativeValidation == "true") { + checkRound("400 + 1", native = false) + checkRound("-400 - 1", native = false) + } else { + checkRound("400 + 1") + checkRound("-400 - 1") + } + } + } + } + } +} diff --git a/gluten-ut/spark34/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala b/gluten-ut/spark34/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala index cfb895a79bb..930fe067e1b 100644 --- a/gluten-ut/spark34/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala +++ b/gluten-ut/spark34/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala @@ -49,6 +49,7 @@ import org.apache.spark.sql.sources.{GlutenBucketedReadWithoutHiveSupportSuite, class VeloxTestSettings extends BackendTestSettings { import SuiteSettings._ enableSuite[GlutenStringFunctionsSuite] + enableSuite[GlutenDecimalRoundSuite] enableSuite[GlutenBloomFilterAggregateQuerySuite] enableSuite[GlutenDataSourceV2DataFrameSessionCatalogSuite] enableSuite[GlutenDataSourceV2DataFrameSuite] diff --git a/gluten-ut/spark34/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuite.scala b/gluten-ut/spark34/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuite.scala new file mode 100644 index 00000000000..ba53038ee71 --- /dev/null +++ b/gluten-ut/spark34/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuite.scala @@ -0,0 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.spark.sql + +class GlutenDecimalRoundSuite extends GlutenDecimalRoundSuiteBase diff --git a/gluten-ut/spark35/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala b/gluten-ut/spark35/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala index 08c584714a5..8cc5a15b7af 100644 --- a/gluten-ut/spark35/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala +++ b/gluten-ut/spark35/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala @@ -48,6 +48,7 @@ import org.apache.spark.sql.sources._ class VeloxTestSettings extends BackendTestSettings { import SuiteSettings._ enableSuite[GlutenStringFunctionsSuite] + enableSuite[GlutenDecimalRoundSuite] enableSuite[GlutenBloomFilterAggregateQuerySuite] enableSuite[GlutenBloomFilterAggregateQuerySuiteCGOff] enableSuite[GlutenDataSourceV2DataFrameSessionCatalogSuite] diff --git a/gluten-ut/spark35/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuite.scala b/gluten-ut/spark35/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuite.scala new file mode 100644 index 00000000000..ba53038ee71 --- /dev/null +++ b/gluten-ut/spark35/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuite.scala @@ -0,0 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.spark.sql + +class GlutenDecimalRoundSuite extends GlutenDecimalRoundSuiteBase diff --git a/gluten-ut/spark40/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala b/gluten-ut/spark40/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala index 5693a36a62f..2d37302cb6b 100644 --- a/gluten-ut/spark40/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala +++ b/gluten-ut/spark40/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala @@ -53,6 +53,7 @@ class VeloxTestSettings extends BackendTestSettings { private val ansiNoFallback: Boolean = sys.props.get(GlutenConfig.GLUTEN_ANSI_FALLBACK_ENABLED.key).contains("false") enableSuite[GlutenStringFunctionsSuite] + enableSuite[GlutenDecimalRoundSuite] enableSuite[GlutenBloomFilterAggregateQuerySuite] enableSuite[GlutenBloomFilterAggregateQuerySuiteCGOff] enableSuite[GlutenDataSourceV2DataFrameSessionCatalogSuite] diff --git a/gluten-ut/spark40/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuite.scala b/gluten-ut/spark40/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuite.scala new file mode 100644 index 00000000000..ba53038ee71 --- /dev/null +++ b/gluten-ut/spark40/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuite.scala @@ -0,0 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.spark.sql + +class GlutenDecimalRoundSuite extends GlutenDecimalRoundSuiteBase diff --git a/gluten-ut/spark41/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala b/gluten-ut/spark41/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala index 781cfb2eee1..d0aefae2751 100644 --- a/gluten-ut/spark41/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala +++ b/gluten-ut/spark41/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala @@ -53,6 +53,7 @@ class VeloxTestSettings extends BackendTestSettings { private val ansiNoFallback: Boolean = sys.props.get(GlutenConfig.GLUTEN_ANSI_FALLBACK_ENABLED.key).contains("false") enableSuite[GlutenStringFunctionsSuite] + enableSuite[GlutenDecimalRoundSuite] enableSuite[GlutenBloomFilterAggregateQuerySuite] enableSuite[GlutenBloomFilterAggregateQuerySuiteCGOff] enableSuite[GlutenDataSourceV2DataFrameSessionCatalogSuite] diff --git a/gluten-ut/spark41/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuite.scala b/gluten-ut/spark41/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuite.scala new file mode 100644 index 00000000000..ba53038ee71 --- /dev/null +++ b/gluten-ut/spark41/src/test/scala/org/apache/spark/sql/GlutenDecimalRoundSuite.scala @@ -0,0 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.spark.sql + +class GlutenDecimalRoundSuite extends GlutenDecimalRoundSuiteBase