diff --git a/core/src/main/resources/error/error-classes.json b/core/src/main/resources/error/error-classes.json index fc712fc9c52e3..5eab18dfd352c 100644 --- a/core/src/main/resources/error/error-classes.json +++ b/core/src/main/resources/error/error-classes.json @@ -113,6 +113,12 @@ "message" : [ "The value of parameter(s) '' in is invalid: " ], "sqlState" : "22023" }, + "INVALID_PROPERTY_KEY" : { + "message" : [ " is an invalid property key, please use quotes, e.g. SET =" ] + }, + "INVALID_PROPERTY_VALUE" : { + "message" : [ " is an invalid property value, please use quotes, e.g. SET =" ] + }, "INVALID_SQL_SYNTAX" : { "message" : [ "Invalid SQL syntax: " ], "sqlState" : "42000" 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 6e8124c89e2d6..e92ed3e3b0729 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 @@ -260,17 +260,20 @@ private[sql] object QueryParsingErrors extends QueryErrorsBase { } def cannotCleanReservedNamespacePropertyError( - property: String, ctx: ParserRuleContext, msg: String): Throwable = { - new ParseException(s"$property is a reserved namespace property, $msg.", ctx) + property: String, ctx: ParserRuleContext, msg: String): ParseException = { + new ParseException("UNSUPPORTED_FEATURE", + Array(s"$property is a reserved namespace property, $msg."), ctx) } - def propertiesAndDbPropertiesBothSpecifiedError(ctx: CreateNamespaceContext): Throwable = { - new ParseException("Either PROPERTIES or DBPROPERTIES is allowed.", ctx) + def propertiesAndDbPropertiesBothSpecifiedError(ctx: CreateNamespaceContext): ParseException = { + new ParseException("UNSUPPORTED_FEATURE", + Array("set PROPERTIES and DBPROPERTIES at the same time."), ctx) } def cannotCleanReservedTablePropertyError( - property: String, ctx: ParserRuleContext, msg: String): Throwable = { - new ParseException(s"$property is a reserved table property, $msg.", ctx) + property: String, ctx: ParserRuleContext, msg: String): ParseException = { + new ParseException("UNSUPPORTED_FEATURE", + Array(s"$property is a reserved table property, $msg."), ctx) } def duplicatedTablePathsFoundError( @@ -367,15 +370,17 @@ private[sql] object QueryParsingErrors extends QueryErrorsBase { } def invalidPropertyKeyForSetQuotedConfigurationError( - keyCandidate: String, valueStr: String, ctx: ParserRuleContext): Throwable = { - new ParseException(s"'$keyCandidate' is an invalid property key, please " + - s"use quotes, e.g. SET `$keyCandidate`=`$valueStr`", ctx) + keyCandidate: String, valueStr: String, ctx: ParserRuleContext): ParseException = { + new ParseException(errorClass = "INVALID_PROPERTY_KEY", + messageParameters = Array(toSQLConf(keyCandidate), + toSQLConf(keyCandidate), toSQLConf(valueStr)), ctx) } def invalidPropertyValueForSetQuotedConfigurationError( - valueCandidate: String, keyStr: String, ctx: ParserRuleContext): Throwable = { - new ParseException(s"'$valueCandidate' is an invalid property value, please " + - s"use quotes, e.g. SET `$keyStr`=`$valueCandidate`", ctx) + valueCandidate: String, keyStr: String, ctx: ParserRuleContext): ParseException = { + new ParseException(errorClass = "INVALID_PROPERTY_VALUE", + messageParameters = Array(toSQLConf(valueCandidate), + toSQLConf(keyStr), toSQLConf(valueCandidate)), ctx) } def unexpectedFormatForResetConfigurationError(ctx: ResetConfigurationContext): Throwable = { 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 508f551bcec95..6494e541d4fab 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 @@ -213,4 +213,96 @@ class QueryParsingErrorsSuite extends QueryTest with SharedSparkSession { |--------------------------------------------^^^ |""".stripMargin) } + + test("UNSUPPORTED_FEATURE: cannot set reserved namespace property") { + val sql = "CREATE NAMESPACE IF NOT EXISTS a.b.c WITH PROPERTIES ('location'='/home/user/db')" + val msg = """The feature is not supported: location is a reserved namespace property, """ + + """please use the LOCATION clause to specify it.(line 1, pos 0)""" + validateParsingError( + sqlText = sql, + errorClass = "UNSUPPORTED_FEATURE", + sqlState = "0A000", + message = + s""" + |$msg + | + |== SQL == + |$sql + |^^^ + |""".stripMargin) + } + + test("UNSUPPORTED_FEATURE: cannot set reserved table property") { + val sql = "CREATE TABLE student (id INT, name STRING, age INT) " + + "USING PARQUET TBLPROPERTIES ('provider'='parquet')" + val msg = """The feature is not supported: provider is a reserved table property, """ + + """please use the USING clause to specify it.(line 1, pos 66)""" + validateParsingError( + sqlText = sql, + errorClass = "UNSUPPORTED_FEATURE", + sqlState = "0A000", + message = + s""" + |$msg + | + |== SQL == + |$sql + |------------------------------------------------------------------^^^ + |""".stripMargin) + } + + test("INVALID_PROPERTY_KEY: invalid property key for set quoted configuration") { + val sql = "set =`value`" + val msg = """"" is an invalid property key, please use quotes, """ + + """e.g. SET ""="value"(line 1, pos 0)""" + validateParsingError( + sqlText = sql, + errorClass = "INVALID_PROPERTY_KEY", + sqlState = null, + message = + s""" + |$msg + | + |== SQL == + |$sql + |^^^ + |""".stripMargin) + } + + test("INVALID_PROPERTY_VALUE: invalid property value for set quoted configuration") { + val sql = "set `key`=1;2;;" + val msg = """"1;2;;" is an invalid property value, please use quotes, """ + + """e.g. SET "key"="1;2;;"(line 1, pos 0)""" + validateParsingError( + sqlText = sql, + errorClass = "INVALID_PROPERTY_VALUE", + sqlState = null, + message = + s""" + |$msg + | + |== SQL == + |$sql + |^^^ + |""".stripMargin) + } + + test("UNSUPPORTED_FEATURE: cannot set Properties and DbProperties at the same time") { + val sql = "CREATE NAMESPACE IF NOT EXISTS a.b.c WITH PROPERTIES ('a'='a', 'b'='b', 'c'='c') " + + "WITH DBPROPERTIES('a'='a', 'b'='b', 'c'='c')" + val msg = """The feature is not supported: set PROPERTIES and DBPROPERTIES at the same time.""" + + """(line 1, pos 0)""" + validateParsingError( + sqlText = sql, + errorClass = "UNSUPPORTED_FEATURE", + sqlState = "0A000", + message = + s""" + |$msg + | + |== SQL == + |$sql + |^^^ + |""".stripMargin) + } } diff --git a/sql/core/src/test/scala/org/apache/spark/sql/execution/SparkSqlParserSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/execution/SparkSqlParserSuite.scala index fb8f2ea6d8db2..49f65ab51cd6d 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/execution/SparkSqlParserSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/execution/SparkSqlParserSuite.scala @@ -168,11 +168,11 @@ class SparkSqlParserSuite extends AnalysisTest { intercept("SET a=1;2;;", expectedErrMsg) intercept("SET a b=`1;;`", - "'a b' is an invalid property key, please use quotes, e.g. SET `a b`=`1;;`") + "\"a b\" is an invalid property key, please use quotes, e.g. SET \"a b\"=\"1;;\"") intercept("SET `a`=1;2;;", - "'1;2;;' is an invalid property value, please use quotes, e.g." + - " SET `a`=`1;2;;`") + "\"1;2;;\" is an invalid property value, please use quotes, e.g." + + " SET \"a\"=\"1;2;;\"") } test("refresh resource") { diff --git a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/CreateNamespaceParserSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/CreateNamespaceParserSuite.scala index 69a208b942429..6c59512148a53 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/CreateNamespaceParserSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/CreateNamespaceParserSuite.scala @@ -84,7 +84,8 @@ class CreateNamespaceParserSuite extends AnalysisTest { |WITH PROPERTIES ('a'='a', 'b'='b', 'c'='c') |WITH DBPROPERTIES ('a'='a', 'b'='b', 'c'='c') """.stripMargin - intercept(sql, "Either PROPERTIES or DBPROPERTIES is allowed") + intercept(sql, "The feature is not supported: " + + "set PROPERTIES and DBPROPERTIES at the same time.") } test("create namespace - support for other types in PROPERTIES") {