Skip to content

[SPARK-38985][SQL] Add sub error classes #36307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion core/src/main/resources/error/error-classes.json
Original file line number Diff line number Diff line change
Expand Up @@ -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" : {
Expand Down
35 changes: 31 additions & 4 deletions core/src/main/scala/org/apache/spark/ErrorInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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 = {
Expand Down
3 changes: 1 addition & 2 deletions python/pyspark/sql/tests/test_udf.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,7 @@ def test_udf_not_supported_in_join_condition(self):
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()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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 = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,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 = {
Expand Down Expand Up @@ -757,8 +757,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 = {
Expand Down Expand Up @@ -1884,13 +1883,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")
Expand All @@ -1907,8 +1906,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 = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand All @@ -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)
}

Expand All @@ -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 = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
}

Expand All @@ -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"))
}

Expand Down Expand Up @@ -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"))
}

Expand Down
Loading