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 2ff6914e6ba [SPARK-38913][SQL] Output identifiers in error messages in
SQL style
2ff6914e6ba is described below
commit 2ff6914e6bac053231825c083fd508726a11a349
Author: Max Gekk <[email protected]>
AuthorDate: Sun Apr 17 18:28:49 2022 +0300
[SPARK-38913][SQL] Output identifiers in error messages in SQL style
### What changes were proposed in this pull request?
In the PR, I propose to use backticks to wrap SQL identifiers in error
messages. I added new util functions `toSQLId()` to the trait
`QueryErrorsBase`, and applied it in `Query.*Errors` (also modified tests in
`Query.*ErrorsSuite`). For example:
Before:
```sql
Invalid SQL syntax: The definition of window win is repetitive.
```
After:
```
Invalid SQL syntax: The definition of window `win` is repetitive.
```
### Why are the changes needed?
To improve user experience with Spark SQL. The changes highlight SQL
identifiers in error massages and make them more visible for users.
### Does this PR introduce _any_ user-facing change?
No since error classes haven't been released yet.
### How was this patch tested?
By running the affected test suites:
```
$ build/sbt "test:testOnly *QueryParsingErrorsSuite"
$ build/sbt "test:testOnly *QueryCompilationErrorsSuite"
$ build/sbt "test:testOnly *QueryCompilationErrorsDSv2Suite"
$ build/sbt "test:testOnly *QueryExecutionErrorsSuite"
$ build/sbt "testOnly *PlanParserSuite"
$ build/sbt "testOnly *DDLParserSuite"
$ build/sbt -Phive-2.3 "testOnly *HiveSQLInsertTestSuite"
$ build/sbt "sql/testOnly org.apache.spark.sql.SQLQueryTestSuite -- -z
window.sql"
$ build/sbt "testOnly *DSV2SQLInsertTestSuite"
```
Closes #36210 from MaxGekk/error-class-toSQLId.
Authored-by: Max Gekk <[email protected]>
Signed-off-by: Max Gekk <[email protected]>
---
core/src/main/resources/error/error-classes.json | 2 +-
.../sql/tests/test_pandas_udf_grouped_agg.py | 2 +-
.../spark/sql/errors/QueryCompilationErrors.scala | 9 ++--
.../apache/spark/sql/errors/QueryErrorsBase.scala | 9 ++++
.../spark/sql/errors/QueryExecutionErrors.scala | 8 ++--
.../spark/sql/errors/QueryParsingErrors.scala | 32 +++++++------
.../spark/sql/catalyst/parser/DDLParserSuite.scala | 6 ---
.../sql/catalyst/parser/PlanParserSuite.scala | 12 -----
.../spark/sql/execution/SparkSqlParser.scala | 2 +-
.../resources/sql-tests/results/window.sql.out | 2 +-
.../org/apache/spark/sql/SQLInsertTestSuite.scala | 2 +-
.../errors/QueryCompilationErrorsDSv2Suite.scala | 6 +--
.../sql/errors/QueryCompilationErrorsSuite.scala | 2 +-
.../sql/errors/QueryExecutionErrorsSuite.scala | 8 ++--
.../spark/sql/errors/QueryParsingErrorsSuite.scala | 54 ++++++++++++++++------
.../sql/execution/command/DDLParserSuite.scala | 15 ------
16 files changed, 90 insertions(+), 81 deletions(-)
diff --git a/core/src/main/resources/error/error-classes.json
b/core/src/main/resources/error/error-classes.json
index 397af26302b..a98cd6fc211 100644
--- a/core/src/main/resources/error/error-classes.json
+++ b/core/src/main/resources/error/error-classes.json
@@ -38,7 +38,7 @@
"sqlState" : "22012"
},
"DUPLICATE_KEY" : {
- "message" : [ "Found duplicate keys '%s'" ],
+ "message" : [ "Found duplicate keys %s" ],
"sqlState" : "23000"
},
"FAILED_EXECUTE_UDF" : {
diff --git a/python/pyspark/sql/tests/test_pandas_udf_grouped_agg.py
b/python/pyspark/sql/tests/test_pandas_udf_grouped_agg.py
index fc9be7c2943..56fad6fc1ac 100644
--- a/python/pyspark/sql/tests/test_pandas_udf_grouped_agg.py
+++ b/python/pyspark/sql/tests/test_pandas_udf_grouped_agg.py
@@ -487,7 +487,7 @@ class GroupedAggPandasUDFTests(ReusedSQLTestCase):
with QuietTest(self.sc):
with self.assertRaisesRegex(
AnalysisException,
- "The group aggregate pandas UDF 'avg' cannot be invoked
together with as other, "
+ "The group aggregate pandas UDF `avg` cannot be invoked
together with as other, "
"non-pandas aggregate functions.",
):
df.groupby(df.id).agg(mean_udf(df.v), mean(df.v)).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 479127d8a6b..6b32a08b6fd 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
@@ -46,7 +46,7 @@ import org.apache.spark.sql.types._
* As commands are executed eagerly, this also includes errors thrown during
the execution of
* commands, which users can see immediately.
*/
-object QueryCompilationErrors {
+object QueryCompilationErrors extends QueryErrorsBase {
def groupingIDMismatchError(groupingID: GroupingID, groupByExprs:
Seq[Expression]): Throwable = {
new AnalysisException(
@@ -94,13 +94,14 @@ object QueryCompilationErrors {
def unsupportedIfNotExistsError(tableName: String): Throwable = {
new AnalysisException(
errorClass = "UNSUPPORTED_FEATURE",
- messageParameters = Array(s"IF NOT EXISTS for the table '$tableName' by
INSERT INTO."))
+ messageParameters = Array(
+ s"IF NOT EXISTS for the table ${toSQLId(tableName)} by INSERT INTO."))
}
def nonPartitionColError(partitionName: String): Throwable = {
new AnalysisException(
errorClass = "NON_PARTITION_COLUMN",
- messageParameters = Array(partitionName))
+ messageParameters = Array(toSQLId(partitionName)))
}
def missingStaticPartitionColumn(staticName: String): Throwable = {
@@ -1346,7 +1347,7 @@ object QueryCompilationErrors {
groupAggPandasUDFNames: Seq[String]): Throwable = {
new AnalysisException(
errorClass = "INVALID_PANDAS_UDF_PLACEMENT",
- messageParameters = Array(groupAggPandasUDFNames.map(name =>
s"'$name'").mkString(", ")))
+ messageParameters =
Array(groupAggPandasUDFNames.map(toSQLId).mkString(", ")))
}
def ambiguousAttributesInSelfJoinError(
diff --git
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryErrorsBase.scala
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryErrorsBase.scala
index e69e1382ecf..9b18b59c33d 100644
---
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryErrorsBase.scala
+++
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryErrorsBase.scala
@@ -18,6 +18,7 @@
package org.apache.spark.sql.errors
import org.apache.spark.sql.catalyst.expressions.Literal
+import org.apache.spark.sql.catalyst.util.quoteIdentifier
import org.apache.spark.sql.types.{DataType, DoubleType, FloatType}
trait QueryErrorsBase {
@@ -44,4 +45,12 @@ trait QueryErrorsBase {
def toSQLValue(v: Any, t: DataType): String = {
litToErrorValue(Literal.create(v, t))
}
+
+ def toSQLId(parts: Seq[String]): String = {
+ parts.map(quoteIdentifier).mkString(".")
+ }
+
+ def toSQLId(parts: String): String = {
+ toSQLId(parts.split("\\."))
+ }
}
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 e259103382e..1aef33c6cc2 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
@@ -1894,12 +1894,14 @@ object QueryExecutionErrors extends QueryErrorsBase {
messageParameters = Array("Pivot not after a groupBy."))
}
+ private val aesFuncName = toSQLId("aes_encrypt") + "/" +
toSQLId("aes_decrypt")
+
def invalidAesKeyLengthError(actualLength: Int): RuntimeException = {
new SparkRuntimeException(
errorClass = "INVALID_PARAMETER_VALUE",
messageParameters = Array(
"key",
- "the aes_encrypt/aes_decrypt function",
+ s"the $aesFuncName function",
s"expects a binary value with 16, 24 or 32 bytes, but got
${actualLength.toString} bytes."))
}
@@ -1907,7 +1909,7 @@ object QueryExecutionErrors extends QueryErrorsBase {
new SparkRuntimeException(
errorClass = "UNSUPPORTED_FEATURE",
messageParameters = Array(
- s"AES-$mode with the padding $padding by the aes_encrypt/aes_decrypt
function."))
+ s"AES-$mode with the padding $padding by the $aesFuncName function."))
}
def aesCryptoError(detailMessage: String): RuntimeException = {
@@ -1915,7 +1917,7 @@ object QueryExecutionErrors extends QueryErrorsBase {
errorClass = "INVALID_PARAMETER_VALUE",
messageParameters = Array(
"expr, key",
- "the aes_encrypt/aes_decrypt function",
+ s"the $aesFuncName function",
s"Detail message: $detailMessage"))
}
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 69e118d88bd..ba9c9ecbade 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
@@ -22,13 +22,12 @@ import org.antlr.v4.runtime.ParserRuleContext
import org.apache.spark.sql.catalyst.parser.ParseException
import org.apache.spark.sql.catalyst.parser.SqlBaseParser._
import org.apache.spark.sql.catalyst.trees.Origin
-import org.apache.spark.sql.connector.catalog.CatalogV2Implicits._
/**
* Object for grouping all error messages of the query parsing.
* Currently it includes all ParseException.
*/
-object QueryParsingErrors {
+object QueryParsingErrors extends QueryErrorsBase {
def invalidInsertIntoError(ctx: InsertIntoContext): Throwable = {
new ParseException("Invalid InsertIntoContext", ctx)
@@ -121,17 +120,17 @@ object QueryParsingErrors {
def repetitiveWindowDefinitionError(name: String, ctx: WindowClauseContext):
Throwable = {
new ParseException("INVALID_SQL_SYNTAX",
- Array(s"The definition of window '$name' is repetitive."), ctx)
+ Array(s"The definition of window ${toSQLId(name)} is repetitive."), ctx)
}
def invalidWindowReferenceError(name: String, ctx: WindowClauseContext):
Throwable = {
new ParseException("INVALID_SQL_SYNTAX",
- Array(s"Window reference '$name' is not a window specification."), ctx)
+ Array(s"Window reference ${toSQLId(name)} is not a window
specification."), ctx)
}
def cannotResolveWindowReferenceError(name: String, ctx:
WindowClauseContext): Throwable = {
new ParseException("INVALID_SQL_SYNTAX",
- Array(s"Cannot resolve window reference '$name'."), ctx)
+ Array(s"Cannot resolve window reference ${toSQLId(name)}."), ctx)
}
def naturalCrossJoinUnsupportedError(ctx: RelationContext): Throwable = {
@@ -162,7 +161,7 @@ object QueryParsingErrors {
def functionNameUnsupportedError(functionName: String, ctx:
ParserRuleContext): Throwable = {
new ParseException("INVALID_SQL_SYNTAX",
- Array(s"Unsupported function name '$functionName'"), ctx)
+ Array(s"Unsupported function name ${toSQLId(functionName)}"), ctx)
}
def cannotParseValueTypeError(
@@ -231,7 +230,10 @@ object QueryParsingErrors {
}
def tooManyArgumentsForTransformError(name: String, ctx:
ApplyTransformContext): Throwable = {
- new ParseException("INVALID_SQL_SYNTAX", Array(s"Too many arguments for
transform $name"), ctx)
+ new ParseException(
+ errorClass = "INVALID_SQL_SYNTAX",
+ messageParameters = Array(s"Too many arguments for transform
${toSQLId(name)}"),
+ ctx)
}
def invalidBucketsNumberError(describe: String, ctx: ApplyTransformContext):
Throwable = {
@@ -299,12 +301,13 @@ object QueryParsingErrors {
def showFunctionsUnsupportedError(identifier: String, ctx:
IdentifierContext): Throwable = {
new ParseException("INVALID_SQL_SYNTAX",
- Array(s"SHOW $identifier FUNCTIONS not supported"), ctx)
+ Array(s"SHOW ${toSQLId(identifier)} FUNCTIONS not supported"), ctx)
}
def showFunctionsInvalidPatternError(pattern: String, ctx:
ParserRuleContext): Throwable = {
new ParseException("INVALID_SQL_SYNTAX",
- Array(s"Invalid pattern in SHOW FUNCTIONS: $pattern. It must be a string
literal."), ctx)
+ Array(s"Invalid pattern in SHOW FUNCTIONS: ${toSQLId(pattern)}. " +
+ "It must be a string literal."), ctx)
}
def duplicateCteDefinitionNamesError(duplicateNames: String, ctx:
CtesContext): Throwable = {
@@ -326,7 +329,7 @@ object QueryParsingErrors {
def duplicateKeysError(key: String, ctx: ParserRuleContext): Throwable = {
// Found duplicate keys '$key'
- new ParseException(errorClass = "DUPLICATE_KEY", messageParameters =
Array(key), ctx)
+ new ParseException(errorClass = "DUPLICATE_KEY", messageParameters =
Array(toSQLId(key)), ctx)
}
def unexpectedFomatForSetConfigurationError(ctx: ParserRuleContext):
Throwable = {
@@ -418,9 +421,9 @@ object QueryParsingErrors {
Array("It is not allowed to define a TEMPORARY function with IF NOT
EXISTS."), ctx)
}
- def unsupportedFunctionNameError(quoted: String, ctx:
CreateFunctionContext): Throwable = {
+ def unsupportedFunctionNameError(funcName: Seq[String], ctx:
CreateFunctionContext): Throwable = {
new ParseException("INVALID_SQL_SYNTAX",
- Array(s"Unsupported function name '$quoted'"), ctx)
+ Array(s"Unsupported function name ${toSQLId(funcName)}"), ctx)
}
def specifyingDBInCreateTempFuncError(
@@ -428,7 +431,8 @@ object QueryParsingErrors {
ctx: CreateFunctionContext): Throwable = {
new ParseException(
"INVALID_SQL_SYNTAX",
- Array(s"Specifying a database in CREATE TEMPORARY FUNCTION is not
allowed: '$databaseName'"),
+ Array("Specifying a database in CREATE TEMPORARY FUNCTION is not
allowed: " +
+ toSQLId(databaseName)),
ctx)
}
@@ -442,7 +446,7 @@ object QueryParsingErrors {
def invalidNameForDropTempFunc(name: Seq[String], ctx: ParserRuleContext):
Throwable = {
new ParseException("INVALID_SQL_SYNTAX",
- Array(s"DROP TEMPORARY FUNCTION requires a single part name but got:
${name.quoted}"), ctx)
+ Array(s"DROP TEMPORARY FUNCTION requires a single part name but got:
${toSQLId(name)}"), ctx)
}
def defaultColumnNotImplementedYetError(ctx: ParserRuleContext): Throwable =
{
diff --git
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/DDLParserSuite.scala
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/DDLParserSuite.scala
index e6ae07310ac..c350125d1ce 100644
---
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/DDLParserSuite.scala
+++
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/DDLParserSuite.scala
@@ -2049,12 +2049,6 @@ class DDLParserSuite extends AnalysisTest {
comparePlans(
parsePlan("SHOW FUNCTIONS IN db LIKE 'funct*'"),
ShowFunctions(UnresolvedNamespace(Seq("db")), true, true,
Some("funct*")))
- val sql = "SHOW other FUNCTIONS"
- intercept(sql, s"$sql not supported")
- intercept("SHOW FUNCTIONS IN db f1",
- "Invalid pattern in SHOW FUNCTIONS: f1")
- intercept("SHOW FUNCTIONS IN db LIKE f1",
- "Invalid pattern in SHOW FUNCTIONS: f1")
// The legacy syntax.
comparePlans(
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 a138b907b29..3d0d2fea7be 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
@@ -437,18 +437,6 @@ class PlanParserSuite extends AnalysisTest {
| w2 as w1,
| w3 as w1""".stripMargin,
WithWindowDefinition(ws1, plan))
-
- // Fail with no reference.
- intercept(s"$sql window w2 as w1", "Cannot resolve window reference 'w1'")
-
- // Fail when resolved reference is not a window spec.
- intercept(
- s"""$sql
- |window w1 as (partition by a, b order by c rows between 1 preceding
and 1 following),
- | w2 as w1,
- | w3 as w2""".stripMargin,
- "Window reference 'w2' is not a window specification"
- )
}
test("lateral view") {
diff --git
a/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkSqlParser.scala
b/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkSqlParser.scala
index 86756f5eb57..752b3711283 100644
---
a/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkSqlParser.scala
+++
b/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkSqlParser.scala
@@ -563,7 +563,7 @@ class SparkSqlAstBuilder extends AstBuilder {
}
if (functionIdentifier.length > 2) {
- throw
QueryParsingErrors.unsupportedFunctionNameError(functionIdentifier.quoted, ctx)
+ throw
QueryParsingErrors.unsupportedFunctionNameError(functionIdentifier, ctx)
} else if (functionIdentifier.length == 2) {
// Temporary function names should not contain database prefix like
"database.function"
throw
QueryParsingErrors.specifyingDBInCreateTempFuncError(functionIdentifier.head,
ctx)
diff --git a/sql/core/src/test/resources/sql-tests/results/window.sql.out
b/sql/core/src/test/resources/sql-tests/results/window.sql.out
index b5b6895b099..bac00d85c67 100644
--- a/sql/core/src/test/resources/sql-tests/results/window.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/window.sql.out
@@ -898,7 +898,7 @@ struct<>
-- !query output
org.apache.spark.sql.catalyst.parser.ParseException
-Invalid SQL syntax: The definition of window 'w' is repetitive.(line 8, pos 0)
+Invalid SQL syntax: The definition of window `w` is repetitive.(line 8, pos 0)
== SQL ==
SELECT
diff --git
a/sql/core/src/test/scala/org/apache/spark/sql/SQLInsertTestSuite.scala
b/sql/core/src/test/scala/org/apache/spark/sql/SQLInsertTestSuite.scala
index ab5c66dfec7..3ff526bd9db 100644
--- a/sql/core/src/test/scala/org/apache/spark/sql/SQLInsertTestSuite.scala
+++ b/sql/core/src/test/scala/org/apache/spark/sql/SQLInsertTestSuite.scala
@@ -276,7 +276,7 @@ trait SQLInsertTestSuite extends QueryTest with
SQLTestUtils {
val e = intercept[AnalysisException] {
sql("INSERT OVERWRITE t PARTITION (c='2', C='3') VALUES (1)")
}
- assert(e.getMessage.contains("Found duplicate keys 'c'"))
+ assert(e.getMessage.contains("Found duplicate keys `c`"))
}
// The following code is skipped for Hive because columns stored in Hive
Metastore is always
// case insensitive and we cannot create such table in Hive Metastore.
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 042f130d7f5..d58c2b56293 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
@@ -52,7 +52,7 @@ class QueryCompilationErrorsDSv2Suite
checkAnswer(spark.table(tbl), spark.emptyDataFrame)
assert(e.getMessage === "The feature is not supported: " +
- s"IF NOT EXISTS for the table '$tbl' by INSERT INTO.")
+ s"IF NOT EXISTS for the table `testcat`.`ns1`.`ns2`.`tbl` by INSERT
INTO.")
assert(e.getErrorClass === "UNSUPPORTED_FEATURE")
assert(e.getSqlState === "0A000")
}
@@ -69,7 +69,7 @@ class QueryCompilationErrorsDSv2Suite
}
verifyTable(t1, spark.emptyDataFrame)
- assert(e.getMessage === "PARTITION clause cannot contain a non-partition
column name: id")
+ assert(e.getMessage === "PARTITION clause cannot contain a non-partition
column name: `id`")
assert(e.getErrorClass === "NON_PARTITION_COLUMN")
}
}
@@ -84,7 +84,7 @@ class QueryCompilationErrorsDSv2Suite
}
verifyTable(t1, spark.emptyDataFrame)
- assert(e.getMessage === "PARTITION clause cannot contain a non-partition
column name: data")
+ assert(e.getMessage === "PARTITION clause cannot contain a non-partition
column name: `data`")
assert(e.getErrorClass === "NON_PARTITION_COLUMN")
}
}
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 de671df74c8..9eb8f98ed55 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
@@ -126,7 +126,7 @@ class QueryCompilationErrorsSuite extends QueryTest with
SharedSparkSession {
assert(e.errorClass === Some("INVALID_PANDAS_UDF_PLACEMENT"))
assert(e.message ===
- "The group aggregate pandas UDF 'pandas_udf_1', 'pandas_udf_2' cannot be
invoked " +
+ "The group aggregate pandas UDF `pandas_udf_1`, `pandas_udf_2` cannot be
invoked " +
"together with as other, non-pandas aggregate functions.")
}
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 09f655431dc..8f797210904 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
@@ -66,8 +66,8 @@ class QueryExecutionErrorsSuite extends QueryTest
assert(e.getErrorClass === "INVALID_PARAMETER_VALUE")
assert(e.getSqlState === "22023")
assert(e.getMessage.matches(
- "The value of parameter\\(s\\) 'key' in the aes_encrypt/aes_decrypt
function is invalid: " +
- "expects a binary value with 16, 24 or 32 bytes, but got \\d+ bytes."))
+ "The value of parameter\\(s\\) 'key' in the
`aes_encrypt`/`aes_decrypt` function " +
+ "is invalid: expects a binary value with 16, 24 or 32 bytes, but got
\\d+ bytes."))
}
// Encryption failure - invalid key length
@@ -100,7 +100,7 @@ class QueryExecutionErrorsSuite extends QueryTest
assert(e.getErrorClass === "INVALID_PARAMETER_VALUE")
assert(e.getSqlState === "22023")
assert(e.getMessage ===
- "The value of parameter(s) 'expr, key' in the aes_encrypt/aes_decrypt
function " +
+ "The value of parameter(s) 'expr, key' in the
`aes_encrypt`/`aes_decrypt` function " +
"is invalid: Detail message: " +
"Given final block not properly padded. " +
"Such issues can arise if a bad key is used during decryption.")
@@ -118,7 +118,7 @@ class QueryExecutionErrorsSuite extends QueryTest
assert(e.getErrorClass === "UNSUPPORTED_FEATURE")
assert(e.getSqlState === "0A000")
assert(e.getMessage.matches("""The feature is not supported: AES-\w+
with the padding \w+""" +
- " by the aes_encrypt/aes_decrypt function."))
+ " by the `aes_encrypt`/`aes_decrypt` function."))
}
// Unsupported AES mode and padding in encrypt
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 fe92eab20f7..29ed18071a4 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
@@ -132,7 +132,7 @@ class QueryParsingErrorsSuite extends QueryTest with
SharedSparkSession {
sqlState = "42000",
message =
"""
- |Invalid SQL syntax: The definition of window 'win' is
repetitive.(line 1, pos 31)
+ |Invalid SQL syntax: The definition of window `win` is
repetitive.(line 1, pos 31)
|
|== SQL ==
|SELECT min(a) OVER win FROM t1 WINDOW win AS win, win AS win2
@@ -147,7 +147,7 @@ class QueryParsingErrorsSuite extends QueryTest with
SharedSparkSession {
sqlState = "42000",
message =
"""
- |Invalid SQL syntax: Window reference 'win' is not a window
specification.(line 1, pos 31)
+ |Invalid SQL syntax: Window reference `win` is not a window
specification.(line 1, pos 31)
|
|== SQL ==
|SELECT min(a) OVER win FROM t1 WINDOW win AS win
@@ -162,7 +162,7 @@ class QueryParsingErrorsSuite extends QueryTest with
SharedSparkSession {
sqlState = "42000",
message =
"""
- |Invalid SQL syntax: Cannot resolve window reference 'win2'.(line 1,
pos 31)
+ |Invalid SQL syntax: Cannot resolve window reference `win2`.(line 1,
pos 31)
|
|== SQL ==
|SELECT min(a) OVER win FROM t1 WINDOW win AS win2
@@ -211,7 +211,7 @@ class QueryParsingErrorsSuite extends QueryTest with
SharedSparkSession {
sqlState = "42000",
message =
"""
- |Invalid SQL syntax: Too many arguments for transform years(line 1,
pos 44)
+ |Invalid SQL syntax: Too many arguments for transform `years`(line
1, pos 44)
|
|== SQL ==
|CREATE TABLE table(col int) PARTITIONED BY (years(col,col))
@@ -226,7 +226,7 @@ class QueryParsingErrorsSuite extends QueryTest with
SharedSparkSession {
sqlState = "42000",
message =
"""
- |Invalid SQL syntax: Unsupported function name 'ns.db.func'(line 1,
pos 14)
+ |Invalid SQL syntax: Unsupported function name `ns`.`db`.`func`(line
1, pos 14)
|
|== SQL ==
|SELECT * FROM ns.db.func()
@@ -241,7 +241,7 @@ class QueryParsingErrorsSuite extends QueryTest with
SharedSparkSession {
sqlState = "42000",
message =
"""
- |Invalid SQL syntax: SHOW sys FUNCTIONS not supported(line 1, pos 5)
+ |Invalid SQL syntax: SHOW `sys` FUNCTIONS not supported(line 1, pos
5)
|
|== SQL ==
|SHOW sys FUNCTIONS
@@ -249,23 +249,34 @@ class QueryParsingErrorsSuite extends QueryTest with
SharedSparkSession {
|""".stripMargin)
}
+ // scalastyle:off line.size.limit
test("INVALID_SQL_SYNTAX: Invalid pattern in show functions") {
- val errorDesc =
- "Invalid pattern in SHOW FUNCTIONS: f1. It must be a string
literal.(line 1, pos 21)"
-
validateParsingError(
sqlText = "SHOW FUNCTIONS IN db f1",
errorClass = "INVALID_SQL_SYNTAX",
sqlState = "42000",
message =
s"""
- |Invalid SQL syntax: $errorDesc
+ |Invalid SQL syntax: Invalid pattern in SHOW FUNCTIONS: `f1`. It
must be a string literal.(line 1, pos 21)
|
|== SQL ==
|SHOW FUNCTIONS IN db f1
|---------------------^^^
|""".stripMargin)
+ validateParsingError(
+ sqlText = "SHOW FUNCTIONS IN db LIKE f1",
+ errorClass = "INVALID_SQL_SYNTAX",
+ sqlState = "42000",
+ message =
+ s"""
+ |Invalid SQL syntax: Invalid pattern in SHOW FUNCTIONS: `f1`. It
must be a string literal.(line 1, pos 26)
+ |
+ |== SQL ==
+ |SHOW FUNCTIONS IN db LIKE f1
+ |--------------------------^^^
+ |""".stripMargin)
}
+ // scalastyle:on line.size.limit
test("INVALID_SQL_SYNTAX: Create function with both if not exists and
replace") {
val sqlText =
@@ -335,7 +346,7 @@ class QueryParsingErrorsSuite extends QueryTest with
SharedSparkSession {
sqlState = "42000",
message =
"""
- |Invalid SQL syntax: Unsupported function name 'ns.db.func'(line 2,
pos 0)
+ |Invalid SQL syntax: Unsupported function name `ns`.`db`.`func`(line
2, pos 0)
|
|== SQL ==
|
@@ -354,7 +365,7 @@ class QueryParsingErrorsSuite extends QueryTest with
SharedSparkSession {
|JAR '/path/to/jar2'
|""".stripMargin
val errorDesc =
- "Specifying a database in CREATE TEMPORARY FUNCTION is not allowed:
'db'(line 2, pos 0)"
+ "Specifying a database in CREATE TEMPORARY FUNCTION is not allowed:
`db`(line 2, pos 0)"
validateParsingError(
sqlText = sqlText,
@@ -375,7 +386,7 @@ class QueryParsingErrorsSuite extends QueryTest with
SharedSparkSession {
test("INVALID_SQL_SYNTAX: Drop temporary function requires a single part
name") {
val errorDesc =
- "DROP TEMPORARY FUNCTION requires a single part name but got:
db.func(line 1, pos 0)"
+ "DROP TEMPORARY FUNCTION requires a single part name but got:
`db`.`func`(line 1, pos 0)"
validateParsingError(
sqlText = "DROP TEMPORARY FUNCTION db.func",
@@ -398,11 +409,26 @@ class QueryParsingErrorsSuite extends QueryTest with
SharedSparkSession {
sqlState = "23000",
message =
"""
- |Found duplicate keys 'p1'(line 1, pos 29)
+ |Found duplicate keys `p1`(line 1, pos 29)
|
|== SQL ==
|INSERT OVERWRITE TABLE table PARTITION(p1='1', p1='1') SELECT
'col1', 'col2'
|-----------------------------^^^
|""".stripMargin)
}
+
+ test("DUPLICATE_KEY: in table properties") {
+ validateParsingError(
+ sqlText = "ALTER TABLE dbx.tab1 SET TBLPROPERTIES ('key1' = '1', 'key1'
= '2')",
+ errorClass = "DUPLICATE_KEY",
+ sqlState = "23000",
+ message =
+ """
+ |Found duplicate keys `key1`(line 1, pos 39)
+ |
+ |== SQL ==
+ |ALTER TABLE dbx.tab1 SET TBLPROPERTIES ('key1' = '1', 'key1' = '2')
+ |---------------------------------------^^^
+ |""".stripMargin)
+ }
}
diff --git
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLParserSuite.scala
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLParserSuite.scala
index 25802e554d6..05378e32296 100644
---
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLParserSuite.scala
+++
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLParserSuite.scala
@@ -200,21 +200,6 @@ class DDLParserSuite extends AnalysisTest with
SharedSparkSession {
assert(parsed.isInstanceOf[Project])
}
- test("duplicate keys in table properties") {
- val e = intercept[ParseException] {
- parser.parsePlan("ALTER TABLE dbx.tab1 SET TBLPROPERTIES ('key1' = '1',
'key1' = '2')")
- }.getMessage
- assert(e.contains("Found duplicate keys 'key1'"))
- }
-
- test("duplicate columns in partition specs") {
- val e = intercept[ParseException] {
- parser.parsePlan(
- "ALTER TABLE dbx.tab1 PARTITION (a='1', a='2') RENAME TO PARTITION
(a='100', a='200')")
- }.getMessage
- assert(e.contains("Found duplicate keys 'a'"))
- }
-
test("unsupported operations") {
intercept[ParseException] {
parser.parsePlan(
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]