This is an automated email from the ASF dual-hosted git repository.
sunchao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-comet.git
The following commit(s) were added to refs/heads/main by this push:
new df632c3bd4 test: strengthen ANSI exception assertions (#5800)
df632c3bd4 is described below
commit df632c3bd4a8f098580e98911ce46a92ca122a2c
Author: KUAN-HAO HUANG <[email protected]>
AuthorDate: Thu Sep 10 08:19:52 2026 +0800
test: strengthen ANSI exception assertions (#5800)
---
.../apache/comet/CometArrayExpressionSuite.scala | 32 +++++-------------
.../org/apache/comet/CometExpressionSuite.scala | 39 ++++------------------
.../org/apache/comet/CometNativeCastSuite.scala | 11 ++----
.../scala/org/apache/spark/sql/CometTestBase.scala | 27 +++++++++++++++
4 files changed, 45 insertions(+), 64 deletions(-)
diff --git
a/spark/src/test/scala/org/apache/comet/CometArrayExpressionSuite.scala
b/spark/src/test/scala/org/apache/comet/CometArrayExpressionSuite.scala
index 5f769dab9c..ad86dd15bc 100644
--- a/spark/src/test/scala/org/apache/comet/CometArrayExpressionSuite.scala
+++ b/spark/src/test/scala/org/apache/comet/CometArrayExpressionSuite.scala
@@ -1127,15 +1127,9 @@ class CometArrayExpressionSuite extends CometTestBase
with AdaptiveSparkPlanHelp
sql("CREATE TABLE test_array_get_item(arr ARRAY<INT>) USING parquet")
sql("INSERT INTO test_array_get_item VALUES (array(1, 2, 3))")
// Try to access array with out-of-bounds index
- val exception = intercept[Exception] {
- sql("select arr[5] from test_array_get_item").collect()
- }
+ val exception =
+ checkSparkError(sql("select arr[5] from test_array_get_item"),
"INVALID_ARRAY_INDEX")
val errorMessage = exception.getMessage
- // Verify error message contains the expected error code
- assert(
- errorMessage.contains("INVALID_ARRAY_INDEX"),
- s"Error message should contain array index error: $errorMessage")
-
assert(errorMessage.contains("The index 5 is out of bounds. The array
has 3 elements." +
" Use the SQL function `get()` to tolerate accessing element at
invalid index and return NULL instead."))
@@ -1156,15 +1150,10 @@ class CometArrayExpressionSuite extends CometTestBase
with AdaptiveSparkPlanHelp
sql("CREATE TABLE test_element_at_invalid(arr ARRAY<INT>) USING
parquet")
sql("INSERT INTO test_element_at_invalid VALUES (array(1, 2, 3))")
// Try to access array with out-of-bounds index using element_at
- val exception = intercept[Exception] {
- sql("select element_at(arr, 10) from
test_element_at_invalid").collect()
- }
+ val exception = checkSparkError(
+ sql("select element_at(arr, 10) from test_element_at_invalid"),
+ "INVALID_ARRAY_INDEX_IN_ELEMENT_AT")
val errorMessage = exception.getMessage
- // Verify error message contains the expected error code
- assert(
- errorMessage.contains("INVALID_ARRAY_INDEX_IN_ELEMENT_AT"),
- s"Error message should contain array index error: $errorMessage")
-
assert(errorMessage.contains("The index 10 is out of bounds. The array
has 3 elements." +
" Use `try_element_at` to tolerate accessing element at invalid
index and return NULL instead"))
@@ -1185,15 +1174,10 @@ class CometArrayExpressionSuite extends CometTestBase
with AdaptiveSparkPlanHelp
sql("CREATE TABLE test_element_at_zero(arr ARRAY<INT>) USING parquet")
sql("INSERT INTO test_element_at_zero VALUES (array(1, 2, 3))")
// Try to access array with zero index (invalid in Spark)
- val exception = intercept[Exception] {
- sql("select element_at(arr, 0) from test_element_at_zero").collect()
- }
+ val exception = checkSparkError(
+ sql("select element_at(arr, 0) from test_element_at_zero"),
+ "INVALID_INDEX_OF_ZERO")
val errorMessage = exception.getMessage
- // Verify error message contains the expected error code
- assert(
- errorMessage.contains("INVALID_INDEX_OF_ZERO"),
- s"Error message should contain zero index error: $errorMessage")
-
assert(
errorMessage.contains("The index 0 is invalid. An index shall be
either < 0 or > 0" +
" (the first element has index 1)"))
diff --git a/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
b/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
index 25b43d9fe6..4ab86b4f37 100644
--- a/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
+++ b/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
@@ -39,8 +39,6 @@ import org.apache.comet.testing.{DataGenOptions,
FuzzDataGenerator}
class CometExpressionSuite extends CometTestBase with AdaptiveSparkPlanHelper {
import testImplicits._
- val ARITHMETIC_OVERFLOW_EXCEPTION_MSG =
- """[ARITHMETIC_OVERFLOW] integer overflow. If necessary set
"spark.sql.ansi.enabled" to "false" to bypass this error"""
val DIVIDE_BY_ZERO_EXCEPTION_MSG =
"""Division by zero. Use `try_divide` to tolerate divisor being 0 and
return NULL instead"""
@@ -2944,12 +2942,7 @@ class CometExpressionSuite extends CometTestBase with
AdaptiveSparkPlanHelper {
| from tbl
| """.stripMargin)
- checkSparkAnswerMaybeThrows(res) match {
- case (Some(sparkExc), Some(cometExc)) =>
-
assert(cometExc.getMessage.contains(ARITHMETIC_OVERFLOW_EXCEPTION_MSG))
- assert(sparkExc.getMessage.contains("overflow"))
- case _ => fail("Exception should be thrown")
- }
+ checkSparkError(res, "ARITHMETIC_OVERFLOW")
}
}
}
@@ -2964,12 +2957,7 @@ class CometExpressionSuite extends CometTestBase with
AdaptiveSparkPlanHelper {
| _1 - _2
| from tbl
| """.stripMargin)
- checkSparkAnswerMaybeThrows(res) match {
- case (Some(sparkExc), Some(cometExc)) =>
-
assert(cometExc.getMessage.contains(ARITHMETIC_OVERFLOW_EXCEPTION_MSG))
- assert(sparkExc.getMessage.contains("overflow"))
- case _ => fail("Exception should be thrown")
- }
+ checkSparkError(res, "ARITHMETIC_OVERFLOW")
}
}
}
@@ -2985,12 +2973,7 @@ class CometExpressionSuite extends CometTestBase with
AdaptiveSparkPlanHelper {
| from tbl
| """.stripMargin)
- checkSparkAnswerMaybeThrows(res) match {
- case (Some(sparkExc), Some(cometExc)) =>
-
assert(cometExc.getMessage.contains(ARITHMETIC_OVERFLOW_EXCEPTION_MSG))
- assert(sparkExc.getMessage.contains("overflow"))
- case _ => fail("Exception should be thrown")
- }
+ checkSparkError(res, "ARITHMETIC_OVERFLOW")
}
}
}
@@ -3005,12 +2988,7 @@ class CometExpressionSuite extends CometTestBase with
AdaptiveSparkPlanHelper {
| from tbl
| """.stripMargin)
- checkSparkAnswerMaybeThrows(res) match {
- case (Some(sparkExc), Some(cometExc)) =>
- assert(cometExc.getMessage.contains(DIVIDE_BY_ZERO_EXCEPTION_MSG))
- assert(sparkExc.getMessage.contains("Division by zero"))
- case _ => fail("Exception should be thrown")
- }
+ checkSparkError(res, "DIVIDE_BY_ZERO")
}
}
}
@@ -3025,12 +3003,7 @@ class CometExpressionSuite extends CometTestBase with
AdaptiveSparkPlanHelper {
| from tbl
| """.stripMargin)
- checkSparkAnswerMaybeThrows(res) match {
- case (Some(sparkExc), Some(cometExc)) =>
- assert(cometExc.getMessage.contains(DIVIDE_BY_ZERO_EXCEPTION_MSG))
- assert(sparkExc.getMessage.contains("Division by zero"))
- case _ => fail("Exception should be thrown")
- }
+ checkSparkError(res, "DIVIDE_BY_ZERO")
}
}
}
@@ -3046,6 +3019,8 @@ class CometExpressionSuite extends CometTestBase with
AdaptiveSparkPlanHelper {
| from tbl
| """.stripMargin)
+ // Integral divide still raises an unconverted Arrow error under
ANSI.
+ // https://github.com/apache/datafusion-comet/issues/5072
checkSparkAnswerMaybeThrows(res) match {
case (Some(sparkException), Some(cometException)) =>
assert(sparkException.getMessage.contains(DIVIDE_BY_ZERO_EXCEPTION_MSG))
diff --git a/spark/src/test/scala/org/apache/comet/CometNativeCastSuite.scala
b/spark/src/test/scala/org/apache/comet/CometNativeCastSuite.scala
index 2a2854ece3..e96367bfe5 100644
--- a/spark/src/test/scala/org/apache/comet/CometNativeCastSuite.scala
+++ b/spark/src/test/scala/org/apache/comet/CometNativeCastSuite.scala
@@ -1382,15 +1382,9 @@ class CometNativeCastSuite extends CometTestBase with
AdaptiveSparkPlanHelper {
// Create a table with string data using DataFrame API
Seq("a").toDF("s").write.format("parquet").saveAsTable("cast_error_msg")
// Try to cast invalid string to date - should throw exception with
SQL context
- val exception = intercept[Exception] {
- sql("select cast(s as date) from cast_error_msg").collect()
- }
+ val exception =
+ checkSparkError(sql("select cast(s as date) from cast_error_msg"),
"CAST_INVALID_INPUT")
val errorMessage = exception.getMessage
- // Verify error message contains the cast invalid input error
- assert(
- errorMessage.contains("CAST_INVALID_INPUT") ||
- errorMessage.contains("cannot be cast to"),
- s"Error message should contain cast error: $errorMessage")
assert(
errorMessage.contains("select cast(s as date) from cast_error_msg"),
@@ -2873,6 +2867,7 @@ class CometNativeCastSuite extends CometTestBase with
AdaptiveSparkPlanHelper {
val cometMessage =
if (cometException.getCause != null)
cometException.getCause.getMessage
else cometException.getMessage
+ // https://github.com/apache/datafusion-comet/issues/5072
// this if branch should only check decimal to decimal cast and
errors when output precision, scale causes overflow.
if (df.schema("a").dataType.typeName.contains("decimal") &&
toType.typeName
.contains("decimal") && sparkMessage.contains("cannot be
represented as")) {
diff --git a/spark/src/test/scala/org/apache/spark/sql/CometTestBase.scala
b/spark/src/test/scala/org/apache/spark/sql/CometTestBase.scala
index 975ba509cc..39a2044b20 100644
--- a/spark/src/test/scala/org/apache/spark/sql/CometTestBase.scala
+++ b/spark/src/test/scala/org/apache/spark/sql/CometTestBase.scala
@@ -366,6 +366,33 @@ abstract class CometTestBase
}
}
+ /** Checks native execution and Spark exception type, error class and
SQLSTATE parity. */
+ protected def checkSparkError(
+ df: DataFrame,
+ errorClass: String): SparkThrowable with Throwable = {
+ checkCometOperators(stripAQEPlan(df.queryExecution.executedPlan))
+ val (sparkError, cometError) = checkSparkAnswerMaybeThrows(df)
+
+ def structuredError(
+ error: Option[Throwable],
+ engine: String): SparkThrowable with Throwable = {
+ val failure = error.getOrElse(fail(s"$engine did not fail with
$errorClass"))
+ val chain = causeChain(failure)
+ assert(!chain.exists(_.isInstanceOf[CometNativeException]), s"$engine:
$failure")
+ chain.collect { case e: SparkThrowable with Throwable => e
}.lastOption.getOrElse {
+ fail(s"$engine did not throw a SparkThrowable: $failure")
+ }
+ }
+
+ val expected = structuredError(sparkError, "Spark")
+ val actual = structuredError(cometError, "Comet")
+ assert(expected.getErrorClass == errorClass)
+ assert(actual.getClass == expected.getClass)
+ assert(actual.getErrorClass == errorClass)
+ assert(actual.getSqlState == expected.getSqlState)
+ actual
+ }
+
/**
* Compares the Comet DataFrame result against the expected Spark answer,
using labels that
* correctly identify which side is Comet and which is Spark. This avoids
the misleading "Spark
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]