This is an automated email from the ASF dual-hosted git repository.
MaxGekk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/master by this push:
new 4810493379f3 [SPARK-57750][SQL] Assign a name to the error condition
_LEGACY_ERROR_TEMP_3084 and set its cause
4810493379f3 is described below
commit 4810493379f3b6e6070ce4b678ed22fed81e134c
Author: Maxim Gekk <[email protected]>
AuthorDate: Tue Jun 30 16:34:57 2026 +0200
[SPARK-57750][SQL] Assign a name to the error condition
_LEGACY_ERROR_TEMP_3084 and set its cause
### What changes were proposed in this pull request?
Replace the legacy error condition `_LEGACY_ERROR_TEMP_3084`, raised when a
Hive UDF/UDAF/UDTF wrapper class fails to instantiate during function
resolution, with the descriptive condition `CANNOT_INSTANTIATE_HIVE_FUNCTION`,
and attach the original failure as the exception cause.
- Add `CANNOT_INSTANTIATE_HIVE_FUNCTION` (SQLSTATE `38000`) to
`error-conditions.json` and remove `_LEGACY_ERROR_TEMP_3084`.
- Add `QueryCompilationErrors.cannotInstantiateHiveFunctionError(clazz, e)`
that passes `cause = Some(e)` so the inner failure is preserved on the
exception chain.
- Update `HiveSessionStateBuilder.makeHiveFunctionExpression` to throw the
new error and drop the manual `setStackTrace` (the attached cause now carries
the inner stack trace).
- Update `HiveUDFSuite` to assert via `checkError` on the new condition,
and to read the inner failure via `getCause` where the wrapped message was
previously asserted.
### Why are the changes needed?
Part of the error-class migration (umbrella
[SPARK-37935](https://issues.apache.org/jira/browse/SPARK-37935)). The legacy
condition used a free-form `e` message parameter and did not attach the cause:
the 2-arg `AnalysisException(errorClass, messageParameters)` constructor sets
`cause = None`, so `getCause` returned `null` and callers/tests could not
programmatically unwrap the inner failure (for example, asserting the inner
condition via `checkError`).
### Does this PR introduce _any_ user-facing change?
Yes. The error condition name and message change, and the original
exception is now attached as the cause. This is a change within the unreleased
`master` branch only.
Before:
```
[_LEGACY_ERROR_TEMP_3084] No handler for UDF/UDAF/UDTF '<clazz>': <e>
```
After:
```
[CANNOT_INSTANTIATE_HIVE_FUNCTION] Cannot instantiate the Hive
UDF/UDAF/UDTF wrapper class <clazz>. Check that the function arguments and
their types are supported. SQLSTATE: 38000
```
### How was this patch tested?
By running:
- `build/sbt "core/testOnly org.apache.spark.SparkThrowableSuite"`
- `build/sbt "hive/testOnly
org.apache.spark.sql.hive.execution.HiveUDFSuite"`
### Was this patch authored or co-authored using generative AI tooling?
Generated-by: Cursor
Closes #56867 from MaxGekk/error-cond_LEGACY_ERROR_TEMP_3084.
Authored-by: Maxim Gekk <[email protected]>
Signed-off-by: Max Gekk <[email protected]>
---
.../src/main/resources/error/error-conditions.json | 11 +++--
.../spark/sql/errors/QueryCompilationErrors.scala | 7 +++
.../spark/sql/hive/HiveSessionStateBuilder.scala | 10 +---
.../scala/org/apache/spark/sql/hive/UDFSuite.scala | 2 +-
.../spark/sql/hive/execution/HiveUDFSuite.scala | 57 ++++++++++++++--------
5 files changed, 53 insertions(+), 34 deletions(-)
diff --git a/common/utils/src/main/resources/error/error-conditions.json
b/common/utils/src/main/resources/error/error-conditions.json
index 64d414b10b64..c80447eab3d8 100644
--- a/common/utils/src/main/resources/error/error-conditions.json
+++ b/common/utils/src/main/resources/error/error-conditions.json
@@ -498,6 +498,12 @@
],
"sqlState" : "22546"
},
+ "CANNOT_INSTANTIATE_HIVE_FUNCTION" : {
+ "message" : [
+ "Cannot instantiate the Hive UDF/UDAF/UDTF wrapper class <clazz>. Check
that the function arguments and their types are supported."
+ ],
+ "sqlState" : "38000"
+ },
"CANNOT_INVOKE_IN_TRANSFORMATIONS" : {
"message" : [
"Dataset transformations and actions can only be invoked by the driver,
not inside of other Dataset transformations; for example, dataset1.map(x =>
dataset2.values.count() * x) is invalid because the values transformation and
count action cannot be performed inside of the dataset1.map transformation. For
more information, see SPARK-28702."
@@ -11336,11 +11342,6 @@
"Unable to infer the schema. The schema specification is required to
create the table <tableName>."
]
},
- "_LEGACY_ERROR_TEMP_3084" : {
- "message" : [
- "No handler for UDF/UDAF/UDTF '<clazz>': <e>"
- ]
- },
"_LEGACY_ERROR_TEMP_3086" : {
"message" : [
"Cannot persist <tableName> into Hive metastore as table property keys
may not start with 'spark.sql.': <invalidKeys>"
diff --git
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryCompilationErrors.scala
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryCompilationErrors.scala
index 80d3e351c639..c54a95eb506a 100644
---
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryCompilationErrors.scala
+++
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryCompilationErrors.scala
@@ -4602,6 +4602,13 @@ private[sql] object QueryCompilationErrors extends
QueryErrorsBase with Compilat
messageParameters = Map("invalidClass" -> invalidClass))
}
+ def cannotInstantiateHiveFunctionError(clazz: String, e: Throwable):
Throwable = {
+ new AnalysisException(
+ errorClass = "CANNOT_INSTANTIATE_HIVE_FUNCTION",
+ messageParameters = Map("clazz" -> clazz),
+ cause = Some(e))
+ }
+
def unsupportedParameterExpression(expr: Expression): Throwable = {
new AnalysisException(
errorClass = "UNSUPPORTED_EXPR_FOR_PARAMETER",
diff --git
a/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveSessionStateBuilder.scala
b/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveSessionStateBuilder.scala
index 0fbc41492e00..44cfd339e15c 100644
---
a/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveSessionStateBuilder.scala
+++
b/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveSessionStateBuilder.scala
@@ -24,7 +24,6 @@ import scala.util.control.NonFatal
import org.apache.hadoop.hive.ql.exec.{UDAF, UDF}
import org.apache.hadoop.hive.ql.udf.generic.{AbstractGenericUDAFResolver,
GenericUDF, GenericUDTF}
-import org.apache.spark.sql.AnalysisException
import org.apache.spark.sql.catalyst.analysis.{Analyzer,
EvalSubqueriesForTimeTravel, InvokeProcedures, ReplaceCharWithVarchar,
ResolveDataSource, ResolveEventTimeWatermark, ResolveExecuteImmediate,
ResolveMetricView, ResolveSessionCatalog, ResolveTranspose}
import org.apache.spark.sql.catalyst.analysis.resolver.ResolverExtension
import org.apache.spark.sql.catalyst.catalog.{ExternalCatalogWithListener,
InvalidUDFClassException}
@@ -246,13 +245,8 @@ object HiveUDFExpressionBuilder extends
SparkUDFExpressionBuilder {
case i: InvocationTargetException => i.getCause
case o => o
}
- val analysisException = new AnalysisException(
- errorClass = "_LEGACY_ERROR_TEMP_3084",
- messageParameters = Map(
- "clazz" -> clazz.getCanonicalName,
- "e" -> e.toString))
- analysisException.setStackTrace(e.getStackTrace)
- throw analysisException
+ throw QueryCompilationErrors.cannotInstantiateHiveFunctionError(
+ clazz.getCanonicalName, e)
}
udfExpr.getOrElse {
throw QueryCompilationErrors.invalidUDFClassError(clazz.getCanonicalName)
diff --git a/sql/hive/src/test/scala/org/apache/spark/sql/hive/UDFSuite.scala
b/sql/hive/src/test/scala/org/apache/spark/sql/hive/UDFSuite.scala
index ef8ae7a408fb..d8c0848ccae3 100644
--- a/sql/hive/src/test/scala/org/apache/spark/sql/hive/UDFSuite.scala
+++ b/sql/hive/src/test/scala/org/apache/spark/sql/hive/UDFSuite.scala
@@ -204,7 +204,7 @@ class UDFSuite
sql(s"SELECT $functionName(value) from $testTableName")
}
- assert(e.getMessage.contains("Can not get an evaluator of the empty
UDAF"))
+ assert(e.getCause.getMessage.contains("Can not get an evaluator of the
empty UDAF"))
}
}
diff --git
a/sql/hive/src/test/scala/org/apache/spark/sql/hive/execution/HiveUDFSuite.scala
b/sql/hive/src/test/scala/org/apache/spark/sql/hive/execution/HiveUDFSuite.scala
index 6a44e17296c0..35ae3ea29d6d 100644
---
a/sql/hive/src/test/scala/org/apache/spark/sql/hive/execution/HiveUDFSuite.scala
+++
b/sql/hive/src/test/scala/org/apache/spark/sql/hive/execution/HiveUDFSuite.scala
@@ -290,8 +290,10 @@ class HiveUDFSuite extends QueryTest with
TestHiveSingleton {
sql(s"CREATE TEMPORARY FUNCTION testUDFRawList " +
s"AS '${classOf[UDFRawList].getName}'")
val err = intercept[AnalysisException](sql("SELECT testUDFRawList(s) FROM
inputTable"))
- assert(err.getMessage.contains(
- "Raw list type in java is unsupported because Spark cannot infer the
element type."))
+ checkError(
+ exception = err.getCause.asInstanceOf[AnalysisException],
+ condition = "_LEGACY_ERROR_TEMP_3090",
+ parameters = Map.empty)
sql("DROP TEMPORARY FUNCTION IF EXISTS testUDFRawList")
hiveContext.reset()
@@ -304,8 +306,10 @@ class HiveUDFSuite extends QueryTest with
TestHiveSingleton {
sql(s"CREATE TEMPORARY FUNCTION testUDFRawMap " +
s"AS '${classOf[UDFRawMap].getName}'")
val err = intercept[AnalysisException](sql("SELECT testUDFRawMap(s) FROM
inputTable"))
- assert(err.getMessage.contains(
- "Raw map type in java is unsupported because Spark cannot infer key and
value types."))
+ checkError(
+ exception = err.getCause.asInstanceOf[AnalysisException],
+ condition = "_LEGACY_ERROR_TEMP_3091",
+ parameters = Map.empty)
sql("DROP TEMPORARY FUNCTION IF EXISTS testUDFRawMap")
hiveContext.reset()
@@ -318,9 +322,10 @@ class HiveUDFSuite extends QueryTest with
TestHiveSingleton {
sql(s"CREATE TEMPORARY FUNCTION testUDFWildcardList " +
s"AS '${classOf[UDFWildcardList].getName}'")
val err = intercept[AnalysisException](sql("SELECT testUDFWildcardList(s)
FROM inputTable"))
- assert(err.getMessage.contains(
- "Collection types with wildcards (e.g. List<?> or Map<?, ?>) are
unsupported " +
- "because Spark cannot infer the data type for these type parameters."))
+ checkError(
+ exception = err.getCause.asInstanceOf[AnalysisException],
+ condition = "_LEGACY_ERROR_TEMP_3092",
+ parameters = Map.empty)
sql("DROP TEMPORARY FUNCTION IF EXISTS testUDFWildcardList")
hiveContext.reset()
@@ -414,10 +419,16 @@ class HiveUDFSuite extends QueryTest with
TestHiveSingleton {
def testErrorMsgForFunc(funcName: String, className: String): Unit = {
withUserDefinedFunction(funcName -> true) {
sql(s"CREATE TEMPORARY FUNCTION $funcName AS '$className'")
- val message = intercept[AnalysisException] {
- sql(s"SELECT $funcName() FROM testUDF")
- }.getMessage
- assert(message.contains(s"No handler for UDF/UDAF/UDTF
'$className'"))
+ checkError(
+ exception = intercept[AnalysisException] {
+ sql(s"SELECT $funcName() FROM testUDF")
+ },
+ condition = "CANNOT_INSTANTIATE_HIVE_FUNCTION",
+ parameters = Map("clazz" -> className),
+ context = ExpectedContext(
+ fragment = s"$funcName()",
+ start = 7,
+ stop = 6 + s"$funcName()".length))
}
}
@@ -678,15 +689,21 @@ class HiveUDFSuite extends QueryTest with
TestHiveSingleton {
sql("SELECT testArraySum(array(1, 1.1, 1.2))"),
Seq(Row(3.3)))
- val msg = intercept[AnalysisException] {
- sql("SELECT testArraySum(1)")
- }.getMessage
- assert(msg.contains(s"No handler for UDF/UDAF/UDTF
'${classOf[ArraySumUDF].getName}'"))
-
- val msg2 = intercept[AnalysisException] {
- sql("SELECT testArraySum(1, 2)")
- }.getMessage
- assert(msg2.contains(s"No handler for UDF/UDAF/UDTF
'${classOf[ArraySumUDF].getName}'"))
+ checkError(
+ exception = intercept[AnalysisException] {
+ sql("SELECT testArraySum(1)")
+ },
+ condition = "CANNOT_INSTANTIATE_HIVE_FUNCTION",
+ parameters = Map("clazz" -> classOf[ArraySumUDF].getCanonicalName),
+ context = ExpectedContext(fragment = "testArraySum(1)", start = 7,
stop = 21))
+
+ checkError(
+ exception = intercept[AnalysisException] {
+ sql("SELECT testArraySum(1, 2)")
+ },
+ condition = "CANNOT_INSTANTIATE_HIVE_FUNCTION",
+ parameters = Map("clazz" -> classOf[ArraySumUDF].getCanonicalName),
+ context = ExpectedContext(fragment = "testArraySum(1, 2)", start = 7,
stop = 24))
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]