This is an automated email from the ASF dual-hosted git repository.

wenchen 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 6f4e7b6894b [SPARK-38985][SQL] Add sub error classes
6f4e7b6894b is described below

commit 6f4e7b6894b6e1649adc6ec829266be6ff96624e
Author: Serge Rielau <srie...@users.noreply.github.com>
AuthorDate: Wed Apr 27 09:30:23 2022 +0800

    [SPARK-38985][SQL] Add sub error classes
    
    ### What changes were proposed in this pull request?
    
    We support nesting an optional map of "sub error classes" in 
error-classes.json.
    Each sub class has a distinct message and independent parameters.
    
    ### Why are the changes needed?
    
    A select subset of error classes have a large variety of error messages 
which cannot be easily tokenized.
    But we do not want to split them because the conditions are often 
temporary. An example is UNSUPPORTED_FEATURE.
    Supporting nested error classes allows us to keep the variety of messages 
without exploding the number of error classes.
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes, we will change the error message texts
    
    ### How was this patch tested?
    
    Run all affected error test suites.
    
    Closes #36307 from srielau/SPARK-38985-sub-error-classes.
    
    Lead-authored-by: Serge Rielau <srie...@users.noreply.github.com>
    Co-authored-by: Serge Rielau <serge.rie...@databricks.com>
    Signed-off-by: Wenchen Fan <wenc...@databricks.com>
---
 core/src/main/resources/error/error-classes.json   | 55 +++++++++++++++++++++-
 .../main/scala/org/apache/spark/ErrorInfo.scala    | 35 ++++++++++++--
 python/pyspark/sql/tests/test_udf.py               |  3 +-
 .../spark/sql/errors/QueryCompilationErrors.scala  | 13 ++---
 .../spark/sql/errors/QueryExecutionErrors.scala    | 16 +++----
 .../spark/sql/errors/QueryParsingErrors.scala      | 14 +++---
 .../ExtractPythonUDFFromJoinConditionSuite.scala   |  4 +-
 .../sql/catalyst/parser/PlanParserSuite.scala      |  2 +-
 .../sql-tests/results/join-lateral.sql.out         |  4 +-
 .../resources/sql-tests/results/transform.sql.out  |  4 +-
 .../errors/QueryCompilationErrorsDSv2Suite.scala   |  3 +-
 .../sql/errors/QueryCompilationErrorsSuite.scala   |  9 ++--
 .../spark/sql/errors/QueryErrorsSuiteBase.scala    | 19 ++++++--
 .../sql/errors/QueryExecutionErrorsSuite.scala     | 13 +++--
 .../spark/sql/errors/QueryParsingErrorsSuite.scala | 18 ++++---
 .../execution/SparkScriptTransformationSuite.scala |  2 +-
 16 files changed, 157 insertions(+), 57 deletions(-)

diff --git a/core/src/main/resources/error/error-classes.json 
b/core/src/main/resources/error/error-classes.json
index 9cb4cb222aa..673866e6c35 100644
--- a/core/src/main/resources/error/error-classes.json
+++ b/core/src/main/resources/error/error-classes.json
@@ -187,7 +187,60 @@
     "sqlState" : "0A000"
   },
   "UNSUPPORTED_FEATURE" : {
-    "message" : [ "The feature is not supported: <feature>" ],
+    "message" : [ "The feature is not supported: " ],
+    "subClass" : {
+      "AES_MODE" : {
+        "message" : [ "AES-<mode> with the padding <padding> by the 
<functionName> function." ]
+      },
+      "DISTRIBUTE_BY" : {
+        "message" : [ "DISTRIBUTE BY clause." ]
+      },
+      "INSERT_PARTITION_SPEC_IF_NOT_EXISTS" : {
+        "message" : [ "INSERT INTO <tableName> IF NOT EXISTS in the PARTITION 
spec." ]
+      },
+      "JDBC_TRANSACTION" : {
+        "message" : [ "The target JDBC server does not support transactions 
and can only support ALTER TABLE with a single action." ]
+      },
+      "LATERAL_JOIN_OF_TYPE" : {
+        "message" : [ "<joinType> JOIN with LATERAL correlation." ]
+      },
+      "LATERAL_JOIN_USING" : {
+        "message" : [ "JOIN USING with LATERAL correlation." ]
+      },
+      "LATERAL_NATURAL_JOIN" : {
+        "message" : [ "NATURAL join with LATERAL correlation." ]
+      },
+      "LITERAL_TYPE" : {
+        "message" : [ "Literal for '<value>' of <type>." ]
+      },
+      "NATURAL_CROSS_JOIN" : {
+        "message" : [ "NATURAL CROSS JOIN." ]
+      },
+      "PANDAS_UDAF_IN_PIVOT" : {
+        "message" : [ "Pandas user defined aggregate function in the PIVOT 
clause." ]
+      },
+      "PIVOT_AFTER_GROUP_BY" : {
+        "message" : [ "PIVOT clause following a GROUP BY clause." ]
+      },
+      "PIVOT_TYPE" : {
+        "message" : [ "Pivoting by the value '<value>' of the column data type 
<type>." ]
+      },
+      "PYTHON_UDF_IN_ON_CLAUSE" : {
+        "message" : [ "Python UDF in the ON clause of a <joinType> JOIN." ]
+      },
+      "REPEATED_PIVOT" : {
+        "message" : [ "Repeated PIVOT operation." ]
+      },
+      "TOO_MANY_TYPE_ARGUMENTS_FOR_UDF_CLASS" : {
+        "message" : [ "UDF class with <n> type arguments." ]
+      },
+      "TRANSFORM_DISTINCT_ALL" : {
+        "message" : [ "TRANSFORM with the DISTINCT/ALL clause." ]
+      },
+      "TRANSFORM_NON_HIVE" : {
+        "message" : [ "TRANSFORM with SERDE is only supported in hive mode." ]
+      }
+    },
     "sqlState" : "0A000"
   },
   "UNSUPPORTED_GROUPING_EXPRESSION" : {
diff --git a/core/src/main/scala/org/apache/spark/ErrorInfo.scala 
b/core/src/main/scala/org/apache/spark/ErrorInfo.scala
index bed05b7ab39..a21f33e8833 100644
--- a/core/src/main/scala/org/apache/spark/ErrorInfo.scala
+++ b/core/src/main/scala/org/apache/spark/ErrorInfo.scala
@@ -28,14 +28,30 @@ import com.fasterxml.jackson.module.scala.DefaultScalaModule
 
 import org.apache.spark.util.Utils
 
+/**
+ * Information associated with an error subclass.
+ *
+ * @param subClass SubClass associated with this class.
+ * @param message C-style message format compatible with printf.
+ *                The error message is constructed by concatenating the lines 
with newlines.
+ */
+private[spark] case class ErrorSubInfo(message: Seq[String]) {
+  // For compatibility with multi-line error messages
+  @JsonIgnore
+  val messageFormat: String = message.mkString("\n")
+}
+
 /**
  * Information associated with an error class.
  *
  * @param sqlState SQLSTATE associated with this class.
+ * @param subClass A sequence of subclasses
  * @param message C-style message format compatible with printf.
  *                The error message is constructed by concatenating the lines 
with newlines.
  */
-private[spark] case class ErrorInfo(message: Seq[String], sqlState: 
Option[String]) {
+private[spark] case class ErrorInfo(message: Seq[String],
+                                    subClass: Option[Map[String, 
ErrorSubInfo]],
+                                    sqlState: Option[String]) {
   // For compatibility with multi-line error messages
   @JsonIgnore
   val messageFormat: String = message.mkString("\n")
@@ -58,9 +74,20 @@ private[spark] object SparkThrowableHelper {
   def getMessage(errorClass: String, messageParameters: Array[String]): String 
= {
     val errorInfo = errorClassToInfoMap.getOrElse(errorClass,
       throw new IllegalArgumentException(s"Cannot find error class 
'$errorClass'"))
-    "[" + errorClass + "] " + String.format(
-      errorInfo.messageFormat.replaceAll("<[a-zA-Z0-9_-]+>", "%s"),
-      messageParameters: _*)
+    if (errorInfo.subClass.isDefined) {
+      val subClass = errorInfo.subClass.get
+      val subErrorClass = messageParameters.head
+      val errorSubInfo = subClass.getOrElse(subErrorClass,
+        throw new IllegalArgumentException(s"Cannot find sub error class 
'$subErrorClass'"))
+      val subMessageParameters = messageParameters.tail
+      "[" + errorClass + "." + subErrorClass + "] " + errorInfo.messageFormat +
+        
String.format(errorSubInfo.messageFormat.replaceAll("<[a-zA-Z0-9_-]+>", "%s"),
+          subMessageParameters: _*)
+    } else {
+      "[" + errorClass + "] " + String.format(
+        errorInfo.messageFormat.replaceAll("<[a-zA-Z0-9_-]+>", "%s"),
+        messageParameters: _*)
+    }
   }
 
   def getSqlState(errorClass: String): String = {
diff --git a/python/pyspark/sql/tests/test_udf.py 
b/python/pyspark/sql/tests/test_udf.py
index e40c3ba0d64..52f8814b269 100644
--- a/python/pyspark/sql/tests/test_udf.py
+++ b/python/pyspark/sql/tests/test_udf.py
@@ -258,8 +258,7 @@ class UDFTests(ReusedSQLTestCase):
         def runWithJoinType(join_type, type_string):
             with self.assertRaisesRegex(
                 AnalysisException,
-                """Using PythonUDF in join condition of join type "%s" is not 
supported"""
-                % type_string,
+                """Python UDF in the ON clause of a "%s" JOIN.""" % 
type_string,
             ):
                 left.join(right, [f("a", "b"), left.a1 == right.b1], 
join_type).collect()
 
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 586f32dd4fc..7f212ed5891 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
@@ -94,9 +94,8 @@ object QueryCompilationErrors extends QueryErrorsBase {
   def unsupportedIfNotExistsError(tableName: String): Throwable = {
     new AnalysisException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array(
-        s"${toSQLStmt("IF NOT EXISTS")} for the table ${toSQLId(tableName)} " +
-        s"by ${toSQLStmt("INSERT INTO")}."))
+      messageParameters = Array("INSERT_PARTITION_SPEC_IF_NOT_EXISTS",
+        toSQLId(tableName)))
   }
 
   def nonPartitionColError(partitionName: String): Throwable = {
@@ -202,7 +201,7 @@ object QueryCompilationErrors extends QueryErrorsBase {
   def pandasUDFAggregateNotSupportedInPivotError(): Throwable = {
     new AnalysisException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array("Pandas UDF aggregate expressions don't 
support pivot."))
+      messageParameters = Array("PANDAS_UDAF_IN_PIVOT"))
   }
 
   def aggregateExpressionRequiredForPivotError(sql: String): Throwable = {
@@ -1588,9 +1587,7 @@ object QueryCompilationErrors extends QueryErrorsBase {
   def usePythonUDFInJoinConditionUnsupportedError(joinType: JoinType): 
Throwable = {
     new AnalysisException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array(
-        "Using PythonUDF in join condition of join type " +
-        s"${toSQLStmt(joinType.sql)} is not supported."))
+      messageParameters = Array("PYTHON_UDF_IN_ON_CLAUSE", 
s"${toSQLStmt(joinType.sql)}"))
   }
 
   def conflictingAttributesInJoinConditionError(
@@ -2336,7 +2333,7 @@ object QueryCompilationErrors extends QueryErrorsBase {
   def udfClassWithTooManyTypeArgumentsError(n: Int): Throwable = {
     new AnalysisException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array(s"UDF class with $n type arguments"))
+      messageParameters = Array("TOO_MANY_TYPE_ARGUMENTS_FOR_UDF_CLASS", 
s"$n"))
   }
 
   def classWithoutPublicNonArgumentConstructorError(className: String): 
Throwable = {
diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala
index dd45f62ac09..fe44a0ff54d 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala
@@ -240,14 +240,14 @@ object QueryExecutionErrors extends QueryErrorsBase {
   def literalTypeUnsupportedError(v: Any): RuntimeException = {
     new SparkRuntimeException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array(s"literal for '${v.toString}' of 
${v.getClass.toString}."))
+      messageParameters = Array("LITERAL_TYPE", s"${v.toString}", 
s"${v.getClass.toString}"))
   }
 
   def pivotColumnUnsupportedError(v: Any, dataType: DataType): 
RuntimeException = {
     new SparkRuntimeException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array(
-        s"pivoting by the value '${v.toString}' of the column data type 
${toSQLType(dataType)}."))
+      messageParameters = Array("PIVOT_TYPE",
+        s"${v.toString}", s"${toSQLType(dataType)}"))
   }
 
   def noDefaultForDataTypeError(dataType: DataType): RuntimeException = {
@@ -766,8 +766,7 @@ object QueryExecutionErrors extends QueryErrorsBase {
   def transactionUnsupportedByJdbcServerError(): Throwable = {
     new SparkSQLFeatureNotSupportedException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array("the target JDBC server does not support 
transaction and " +
-        "can only support ALTER TABLE with a single action."))
+      messageParameters = Array("JDBC_TRANSACTION"))
   }
 
   def dataTypeUnsupportedYetError(dataType: DataType): Throwable = {
@@ -1892,13 +1891,13 @@ object QueryExecutionErrors extends QueryErrorsBase {
   def repeatedPivotsUnsupportedError(): Throwable = {
     new SparkUnsupportedOperationException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array(s"Repeated ${toSQLStmt("pivot")}s."))
+      messageParameters = Array("REPEATED_PIVOT"))
   }
 
   def pivotNotAfterGroupByUnsupportedError(): Throwable = {
     new SparkUnsupportedOperationException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array(s"${toSQLStmt("pivot")} not after a 
${toSQLStmt("group by")}."))
+      messageParameters = Array("PIVOT_AFTER_GROUP_BY"))
   }
 
   private val aesFuncName = toSQLId("aes_encrypt") + "/" + 
toSQLId("aes_decrypt")
@@ -1915,8 +1914,7 @@ object QueryExecutionErrors extends QueryErrorsBase {
   def aesModeUnsupportedError(mode: String, padding: String): RuntimeException 
= {
     new SparkRuntimeException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array(
-        s"AES-$mode with the padding $padding by the $aesFuncName function."))
+      messageParameters = Array("AES_MODE", mode, padding, aesFuncName))
   }
 
   def aesCryptoError(detailMessage: String): RuntimeException = {
diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryParsingErrors.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryParsingErrors.scala
index 06030fb53f3..ed5773f4f82 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryParsingErrors.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryParsingErrors.scala
@@ -92,16 +92,14 @@ object QueryParsingErrors extends QueryErrorsBase {
   def transformNotSupportQuantifierError(ctx: ParserRuleContext): Throwable = {
     new ParseException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array(s"${toSQLStmt("TRANSFORM")} does not support" +
-        s" ${toSQLStmt("DISTINCT")}/${toSQLStmt("ALL")} in inputs"),
+      messageParameters = Array("TRANSFORM_DISTINCT_ALL"),
       ctx)
   }
 
   def transformWithSerdeUnsupportedError(ctx: ParserRuleContext): Throwable = {
     new ParseException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array(
-        s"${toSQLStmt("TRANSFORM")} with serde is only supported in hive 
mode"),
+      messageParameters = Array("TRANSFORM_NON_HIVE"),
       ctx)
   }
 
@@ -112,21 +110,21 @@ object QueryParsingErrors extends QueryErrorsBase {
   def lateralJoinWithNaturalJoinUnsupportedError(ctx: ParserRuleContext): 
Throwable = {
     new ParseException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array(s"${toSQLStmt("LATERAL")} join with 
${toSQLStmt("NATURAL")} join."),
+      messageParameters = Array("LATERAL_NATURAL_JOIN"),
       ctx)
   }
 
   def lateralJoinWithUsingJoinUnsupportedError(ctx: ParserRuleContext): 
Throwable = {
     new ParseException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array(s"${toSQLStmt("LATERAL")} join with 
${toSQLStmt("USING")} join."),
+      messageParameters = Array("LATERAL_JOIN_USING"),
       ctx)
   }
 
   def unsupportedLateralJoinTypeError(ctx: ParserRuleContext, joinType: 
String): Throwable = {
     new ParseException(
       errorClass = "UNSUPPORTED_FEATURE",
-      messageParameters = Array(s"${toSQLStmt("LATERAL")} join type 
${toSQLStmt(joinType)}."),
+      messageParameters = Array("LATERAL_JOIN_OF_TYPE", 
s"${toSQLStmt(joinType)}"),
       ctx)
   }
 
@@ -153,7 +151,7 @@ object QueryParsingErrors extends QueryErrorsBase {
   }
 
   def naturalCrossJoinUnsupportedError(ctx: RelationContext): Throwable = {
-    new ParseException("UNSUPPORTED_FEATURE", Array(toSQLStmt("NATURAL CROSS 
JOIN") + "."), ctx)
+    new ParseException("UNSUPPORTED_FEATURE", Array("NATURAL_CROSS_JOIN"), ctx)
   }
 
   def emptyInputForTableSampleError(ctx: ParserRuleContext): Throwable = {
diff --git 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/optimizer/ExtractPythonUDFFromJoinConditionSuite.scala
 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/optimizer/ExtractPythonUDFFromJoinConditionSuite.scala
index f69f782a0a7..b862416ff07 100644
--- 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/optimizer/ExtractPythonUDFFromJoinConditionSuite.scala
+++ 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/optimizer/ExtractPythonUDFFromJoinConditionSuite.scala
@@ -188,8 +188,8 @@ class ExtractPythonUDFFromJoinConditionSuite extends 
PlanTest {
         Optimize.execute(query.analyze)
       }
       assert(e.message ==
-        "[UNSUPPORTED_FEATURE] The feature is not supported: " +
-        s"""Using PythonUDF in join condition of join type "${joinType.sql}" 
is not supported.""")
+        "[UNSUPPORTED_FEATURE.PYTHON_UDF_IN_ON_CLAUSE] The feature is not 
supported: " +
+        s"""Python UDF in the ON clause of a "${joinType.sql}" JOIN.""")
 
       val query2 = testRelationLeft.join(
         testRelationRight,
diff --git 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/PlanParserSuite.scala
 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/PlanParserSuite.scala
index 77fa99b1450..b8c57753209 100644
--- 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/PlanParserSuite.scala
+++ 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/PlanParserSuite.scala
@@ -1253,7 +1253,7 @@ class PlanParserSuite extends AnalysisTest {
         |    "escapeChar" = "\\")
         |FROM testData
       """.stripMargin,
-      "\"TRANSFORM\" with serde is only supported in hive mode")
+      "TRANSFORM with SERDE is only supported in hive mode.")
   }
 
 
diff --git a/sql/core/src/test/resources/sql-tests/results/join-lateral.sql.out 
b/sql/core/src/test/resources/sql-tests/results/join-lateral.sql.out
index 7b00ab1cb92..625607a8db0 100644
--- a/sql/core/src/test/resources/sql-tests/results/join-lateral.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/join-lateral.sql.out
@@ -153,7 +153,7 @@ struct<>
 -- !query output
 org.apache.spark.sql.catalyst.parser.ParseException
 
-[UNSUPPORTED_FEATURE] The feature is not supported: "LATERAL" join with 
"NATURAL" join.(line 1, pos 14)
+[UNSUPPORTED_FEATURE.LATERAL_NATURAL_JOIN] The feature is not supported: 
NATURAL join with LATERAL correlation.(line 1, pos 14)
 
 == SQL ==
 SELECT * FROM t1 NATURAL JOIN LATERAL (SELECT c1 + c2 AS c2)
@@ -167,7 +167,7 @@ struct<>
 -- !query output
 org.apache.spark.sql.catalyst.parser.ParseException
 
-[UNSUPPORTED_FEATURE] The feature is not supported: "LATERAL" join with 
"USING" join.(line 1, pos 14)
+[UNSUPPORTED_FEATURE.LATERAL_JOIN_USING] The feature is not supported: JOIN 
USING with LATERAL correlation.(line 1, pos 14)
 
 == SQL ==
 SELECT * FROM t1 JOIN LATERAL (SELECT c1 + c2 AS c2) USING (c2)
diff --git a/sql/core/src/test/resources/sql-tests/results/transform.sql.out 
b/sql/core/src/test/resources/sql-tests/results/transform.sql.out
index 3d0fdc81b36..6d7d112b352 100644
--- a/sql/core/src/test/resources/sql-tests/results/transform.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/transform.sql.out
@@ -719,7 +719,7 @@ struct<>
 -- !query output
 org.apache.spark.sql.catalyst.parser.ParseException
 
-[UNSUPPORTED_FEATURE] The feature is not supported: "TRANSFORM" does not 
support "DISTINCT"/"ALL" in inputs(line 1, pos 17)
+[UNSUPPORTED_FEATURE.TRANSFORM_DISTINCT_ALL] The feature is not supported: 
TRANSFORM with the DISTINCT/ALL clause.(line 1, pos 17)
 
 == SQL ==
 SELECT TRANSFORM(DISTINCT b, a, c)
@@ -739,7 +739,7 @@ struct<>
 -- !query output
 org.apache.spark.sql.catalyst.parser.ParseException
 
-[UNSUPPORTED_FEATURE] The feature is not supported: "TRANSFORM" does not 
support "DISTINCT"/"ALL" in inputs(line 1, pos 17)
+[UNSUPPORTED_FEATURE.TRANSFORM_DISTINCT_ALL] The feature is not supported: 
TRANSFORM with the DISTINCT/ALL clause.(line 1, pos 17)
 
 == SQL ==
 SELECT TRANSFORM(ALL b, a, c)
diff --git 
a/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryCompilationErrorsDSv2Suite.scala
 
b/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryCompilationErrorsDSv2Suite.scala
index 9fedf14a2a1..f51ec15dce5 100644
--- 
a/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryCompilationErrorsDSv2Suite.scala
+++ 
b/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryCompilationErrorsDSv2Suite.scala
@@ -53,8 +53,9 @@ class QueryCompilationErrorsDSv2Suite
         checkErrorClass(
           exception = e,
           errorClass = "UNSUPPORTED_FEATURE",
+          errorSubClass = Some("INSERT_PARTITION_SPEC_IF_NOT_EXISTS"),
           msg = "The feature is not supported: " +
-            s""""IF NOT EXISTS" for the table `testcat`.`ns1`.`ns2`.`tbl` by 
"INSERT INTO".""",
+            s"""INSERT INTO `testcat`.`ns1`.`ns2`.`tbl` IF NOT EXISTS in the 
PARTITION spec.""",
           sqlState = Some("0A000"))
       }
     }
diff --git 
a/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryCompilationErrorsSuite.scala
 
b/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryCompilationErrorsSuite.scala
index f1325a68366..39f4414b493 100644
--- 
a/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryCompilationErrorsSuite.scala
+++ 
b/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryCompilationErrorsSuite.scala
@@ -165,8 +165,9 @@ class QueryCompilationErrorsSuite
     checkErrorClass(
       exception = e,
       errorClass = "UNSUPPORTED_FEATURE",
+      errorSubClass = Some("PYTHON_UDF_IN_ON_CLAUSE"),
       msg = "The feature is not supported: " +
-        "Using PythonUDF in join condition of join type \"LEFT OUTER\" is not 
supported.",
+        "Python UDF in the ON clause of a \"LEFT OUTER\" JOIN.",
       sqlState = Some("0A000"))
   }
 
@@ -188,8 +189,9 @@ class QueryCompilationErrorsSuite
     checkErrorClass(
       exception = e,
       errorClass = "UNSUPPORTED_FEATURE",
+      errorSubClass = Some("PANDAS_UDAF_IN_PIVOT"),
       msg = "The feature is not supported: " +
-        "Pandas UDF aggregate expressions don't support pivot.",
+        "Pandas user defined aggregate function in the PIVOT clause.",
       sqlState = Some("0A000"))
   }
 
@@ -270,7 +272,8 @@ class QueryCompilationErrorsSuite
     checkErrorClass(
       exception = e,
       errorClass = "UNSUPPORTED_FEATURE",
-      msg = "The feature is not supported: UDF class with 24 type arguments",
+      errorSubClass = Some("TOO_MANY_TYPE_ARGUMENTS_FOR_UDF_CLASS"),
+      msg = "The feature is not supported: UDF class with 24 type arguments.",
       sqlState = Some("0A000"))
   }
 
diff --git 
a/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryErrorsSuiteBase.scala
 
b/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryErrorsSuiteBase.scala
index 2c2fe188e24..eb7871d5559 100644
--- 
a/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryErrorsSuiteBase.scala
+++ 
b/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryErrorsSuiteBase.scala
@@ -25,28 +25,41 @@ trait QueryErrorsSuiteBase extends SharedSparkSession {
   def checkErrorClass(
       exception: Exception with SparkThrowable,
       errorClass: String,
+      errorSubClass: Option[String] = None,
       msg: String,
       sqlState: Option[String] = None,
       matchMsg: Boolean = false): Unit = {
     assert(exception.getErrorClass === errorClass)
     sqlState.foreach(state => exception.getSqlState === state)
+    val fullErrorClass = if (errorSubClass.isDefined) {
+      errorClass + "." + errorSubClass.get
+    } else {
+     errorClass
+    }
     if (matchMsg) {
-      assert(exception.getMessage.matches(s"""\\[$errorClass\\] """ + msg))
+      assert(exception.getMessage.matches(s"""\\[$fullErrorClass\\] """ + msg))
     } else {
-      assert(exception.getMessage === s"""[$errorClass] """ + msg)
+      assert(exception.getMessage === s"""[$fullErrorClass] """ + msg)
     }
   }
 
   def validateParsingError(
       sqlText: String,
       errorClass: String,
+      errorSubClass: Option[String] = None,
       sqlState: String,
       message: String): Unit = {
     val e = intercept[ParseException] {
       sql(sqlText)
     }
+
+    val fullErrorClass = if (errorSubClass.isDefined) {
+      errorClass + "." + errorSubClass.get
+    } else {
+      errorClass
+    }
     assert(e.getErrorClass === errorClass)
     assert(e.getSqlState === sqlState)
-    assert(e.getMessage === s"""\n[$errorClass] """ + message)
+    assert(e.getMessage === s"""\n[$fullErrorClass] """ + message)
   }
 }
diff --git 
a/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryExecutionErrorsSuite.scala
 
b/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryExecutionErrorsSuite.scala
index f84f159f6f0..1105503e138 100644
--- 
a/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryExecutionErrorsSuite.scala
+++ 
b/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryExecutionErrorsSuite.scala
@@ -121,6 +121,7 @@ class QueryExecutionErrorsSuite
           df.collect
         }.getCause.asInstanceOf[SparkRuntimeException],
         errorClass = "UNSUPPORTED_FEATURE",
+        errorSubClass = Some("AES_MODE"),
         msg =
           """The feature is not supported: AES-\w+ with the padding \w+""" +
           " by the `aes_encrypt`/`aes_decrypt` function.",
@@ -143,7 +144,8 @@ class QueryExecutionErrorsSuite
       checkErrorClass(
         exception = intercept[SparkRuntimeException] { lit(v) },
         errorClass = "UNSUPPORTED_FEATURE",
-        msg = """The feature is not supported: literal for '.+' of .+\.""",
+        errorSubClass = Some("LITERAL_TYPE"),
+        msg = """The feature is not supported: Literal for '.+' of .+\.""",
         sqlState = Some("0A000"),
         matchMsg = true)
     }
@@ -160,7 +162,8 @@ class QueryExecutionErrorsSuite
     checkErrorClass(
       exception = e2,
       errorClass = "UNSUPPORTED_FEATURE",
-      msg = "The feature is not supported: pivoting by the value" +
+      errorSubClass = Some("PIVOT_TYPE"),
+      msg = "The feature is not supported: Pivoting by the value" +
         """ '[dotnet,Dummies]' of the column data type "STRUCT<col1: STRING, 
training: STRING>".""",
       sqlState = Some("0A000"))
   }
@@ -177,7 +180,8 @@ class QueryExecutionErrorsSuite
     checkErrorClass(
       exception = e1,
       errorClass = "UNSUPPORTED_FEATURE",
-      msg = """The feature is not supported: Repeated "PIVOT"s.""",
+      errorSubClass = Some("REPEATED_PIVOT"),
+      msg = "The feature is not supported: Repeated PIVOT operation.",
       sqlState = Some("0A000"))
 
     val e2 = intercept[SparkUnsupportedOperationException] {
@@ -190,7 +194,8 @@ class QueryExecutionErrorsSuite
     checkErrorClass(
       exception = e2,
       errorClass = "UNSUPPORTED_FEATURE",
-      msg = """The feature is not supported: "PIVOT" not after a "GROUP 
BY".""",
+      errorSubClass = Some("PIVOT_AFTER_GROUP_BY"),
+      msg = "The feature is not supported: PIVOT clause following a GROUP BY 
clause.",
       sqlState = Some("0A000"))
   }
 
diff --git 
a/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryParsingErrorsSuite.scala
 
b/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryParsingErrorsSuite.scala
index 6ff737ec647..39bf469553f 100644
--- 
a/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryParsingErrorsSuite.scala
+++ 
b/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryParsingErrorsSuite.scala
@@ -27,9 +27,10 @@ class QueryParsingErrorsSuite extends QueryTest with 
QueryErrorsSuiteBase {
     validateParsingError(
       sqlText = "SELECT * FROM t1 NATURAL JOIN LATERAL (SELECT c1 + c2 AS c2)",
       errorClass = "UNSUPPORTED_FEATURE",
+      errorSubClass = Some("LATERAL_NATURAL_JOIN"),
       sqlState = "0A000",
       message =
-        """The feature is not supported: "LATERAL" join with "NATURAL" 
join.(line 1, pos 14)
+        """The feature is not supported: NATURAL join with LATERAL 
correlation.(line 1, pos 14)
           |
           |== SQL ==
           |SELECT * FROM t1 NATURAL JOIN LATERAL (SELECT c1 + c2 AS c2)
@@ -41,9 +42,10 @@ class QueryParsingErrorsSuite extends QueryTest with 
QueryErrorsSuiteBase {
     validateParsingError(
       sqlText = "SELECT * FROM t1 JOIN LATERAL (SELECT c1 + c2 AS c2) USING 
(c2)",
       errorClass = "UNSUPPORTED_FEATURE",
+      errorSubClass = Some("LATERAL_JOIN_USING"),
       sqlState = "0A000",
       message =
-        """The feature is not supported: "LATERAL" join with "USING" 
join.(line 1, pos 14)
+        """The feature is not supported: JOIN USING with LATERAL 
correlation.(line 1, pos 14)
           |
           |== SQL ==
           |SELECT * FROM t1 JOIN LATERAL (SELECT c1 + c2 AS c2) USING (c2)
@@ -56,9 +58,10 @@ class QueryParsingErrorsSuite extends QueryTest with 
QueryErrorsSuiteBase {
       validateParsingError(
         sqlText = s"SELECT * FROM t1 $joinType JOIN LATERAL (SELECT c1 + c2 AS 
c3) ON c2 = c3",
         errorClass = "UNSUPPORTED_FEATURE",
+        errorSubClass = Some("LATERAL_JOIN_OF_TYPE"),
         sqlState = "0A000",
         message =
-          s"""The feature is not supported: "LATERAL" join type 
"$joinType".(line 1, pos 14)
+          s"""The feature is not supported: "$joinType" JOIN with LATERAL 
correlation.(line 1, pos 14)
             |
             |== SQL ==
             |SELECT * FROM t1 $joinType JOIN LATERAL (SELECT c1 + c2 AS c3) ON 
c2 = c3
@@ -94,9 +97,10 @@ class QueryParsingErrorsSuite extends QueryTest with 
QueryErrorsSuiteBase {
     validateParsingError(
       sqlText = "SELECT * FROM a NATURAL CROSS JOIN b",
       errorClass = "UNSUPPORTED_FEATURE",
+      errorSubClass = Some("NATURAL_CROSS_JOIN"),
       sqlState = "0A000",
       message =
-        """The feature is not supported: "NATURAL CROSS JOIN".(line 1, pos 14)
+        """The feature is not supported: NATURAL CROSS JOIN.(line 1, pos 14)
           |
           |== SQL ==
           |SELECT * FROM a NATURAL CROSS JOIN b
@@ -150,9 +154,10 @@ class QueryParsingErrorsSuite extends QueryTest with 
QueryErrorsSuiteBase {
     validateParsingError(
       sqlText = "SELECT TRANSFORM(DISTINCT a) USING 'a' FROM t",
       errorClass = "UNSUPPORTED_FEATURE",
+      errorSubClass = Some("TRANSFORM_DISTINCT_ALL"),
       sqlState = "0A000",
       message =
-        """The feature is not supported: "TRANSFORM" does not support 
"DISTINCT"/"ALL" in inputs(line 1, pos 17)
+        """The feature is not supported: TRANSFORM with the DISTINCT/ALL 
clause.(line 1, pos 17)
           |
           |== SQL ==
           |SELECT TRANSFORM(DISTINCT a) USING 'a' FROM t
@@ -165,9 +170,10 @@ class QueryParsingErrorsSuite extends QueryTest with 
QueryErrorsSuiteBase {
       sqlText = "SELECT TRANSFORM(a) ROW FORMAT SERDE " +
         "'org.apache.hadoop.hive.serde2.OpenCSVSerde' USING 'a' FROM t",
       errorClass = "UNSUPPORTED_FEATURE",
+      errorSubClass = Some("TRANSFORM_NON_HIVE"),
       sqlState = "0A000",
       message =
-        """The feature is not supported: "TRANSFORM" with serde is only 
supported in hive mode(line 1, pos 0)
+      """The feature is not supported: TRANSFORM with SERDE is only supported 
in hive mode.(line 1, pos 0)
           |
           |== SQL ==
           |SELECT TRANSFORM(a) ROW FORMAT SERDE 
'org.apache.hadoop.hive.serde2.OpenCSVSerde' USING 'a' FROM t
diff --git 
a/sql/core/src/test/scala/org/apache/spark/sql/execution/SparkScriptTransformationSuite.scala
 
b/sql/core/src/test/scala/org/apache/spark/sql/execution/SparkScriptTransformationSuite.scala
index 1f431e173b3..200314dd57e 100644
--- 
a/sql/core/src/test/scala/org/apache/spark/sql/execution/SparkScriptTransformationSuite.scala
+++ 
b/sql/core/src/test/scala/org/apache/spark/sql/execution/SparkScriptTransformationSuite.scala
@@ -56,7 +56,7 @@ class SparkScriptTransformationSuite extends 
BaseScriptTransformationSuite with
             |FROM v
           """.stripMargin)
       }.getMessage
-      assert(e.contains("\"TRANSFORM\" with serde is only supported in hive 
mode"))
+      assert(e.contains("TRANSFORM with SERDE is only supported in hive 
mode."))
     }
   }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@spark.apache.org
For additional commands, e-mail: commits-h...@spark.apache.org

Reply via email to