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]

Reply via email to