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 3bf7de099132 [SPARK-48668][SQL] Support ALTER NAMESPACE ... UNSET
PROPERTIES in v2
3bf7de099132 is described below
commit 3bf7de09913233c5d4825c9647d6d442eb42e5aa
Author: panbingkun <[email protected]>
AuthorDate: Fri Jun 28 10:37:08 2024 +0800
[SPARK-48668][SQL] Support ALTER NAMESPACE ... UNSET PROPERTIES in v2
### What changes were proposed in this pull request?
The pr aims to support `ALTER NAMESPACE ... UNSET PROPERTIES` in `v2`.
### Why are the changes needed?
- For `table` and `view`, we can `add`, `update`, or `delete` table's
`properties` using the following SQL:
```
ALTER (TABLE | VIEW) ... SET TBLPROPERTIES ...
ALTER (TABLE | VIEW) ... UNSET TBLPROPERTIES (IF EXISTS)? ...
```
https://github.com/apache/spark/blob/3469ec6b41967b1b4c7b2549174ed0c199815977/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4#L148-L151
- But at the SQL level, there is only `SET` syntax for `namespace`, not
`UNSET` syntax
```
ALTER namespace ... SET (DBPROPERTIES | PROPERTIES) ...
```
https://github.com/apache/spark/blob/3469ec6b41967b1b4c7b2549174ed0c199815977/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4#L106-L107
- In addition, the underlying `SupportsNamespaces` interface supports
deleting properties. I propose adding SQL syntax to facilitate users to use SQL
instead of relying solely on APIs to manipulate the properties of `namespace`
https://github.com/apache/spark/blob/3469ec6b41967b1b4c7b2549174ed0c199815977/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/SupportsNamespaces.java#L127-L137
https://github.com/apache/spark/blob/3469ec6b41967b1b4c7b2549174ed0c199815977/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/NamespaceChange.java#L59-L61
### Does this PR introduce _any_ user-facing change?
Yes, end users can delete the properties of `namespace` through SQL.
### How was this patch tested?
Add new UT.
### Was this patch authored or co-authored using generative AI tooling?
No.
Closes #47038 from panbingkun/SPARK-48668.
Authored-by: panbingkun <[email protected]>
Signed-off-by: Wenchen Fan <[email protected]>
---
docs/sql-ref-syntax-ddl-alter-database.md | 40 ++++++++++-
.../spark/sql/catalyst/parser/SqlBaseParser.g4 | 2 +
.../spark/sql/catalyst/parser/AstBuilder.scala | 2 +-
.../spark/sql/execution/SparkSqlParser.scala | 20 +++++-
.../command/UnsetNamespacePropertiesCommand.scala | 55 ++++++++++++++++
.../spark/sql/execution/command/commands.scala | 3 +-
.../AlterNamespaceSetPropertiesSuiteBase.scala | 17 +++--
.../AlterNamespaceUnsetPropertiesParserSuite.scala | 77 ++++++++++++++++++++++
...> AlterNamespaceUnsetPropertiesSuiteBase.scala} | 76 ++++++++++-----------
.../AlterNamespaceUnsetPropertiesSuiteBase.scala | 45 +++++++++++++
.../v2/AlterNamespaceUnsetPropertiesSuite.scala | 30 +++++++++
.../AlterNamespaceUnsetPropertiesSuite.scala | 29 ++++++++
12 files changed, 350 insertions(+), 46 deletions(-)
diff --git a/docs/sql-ref-syntax-ddl-alter-database.md
b/docs/sql-ref-syntax-ddl-alter-database.md
index 0ac003823643..727fedb19e23 100644
--- a/docs/sql-ref-syntax-ddl-alter-database.md
+++ b/docs/sql-ref-syntax-ddl-alter-database.md
@@ -25,7 +25,7 @@ license: |
`DATABASE`, `SCHEMA` and `NAMESPACE` are interchangeable and one can be used
in place of the others. An error message
is issued if the database is not found in the system.
-### ALTER PROPERTIES
+### SET PROPERTIES
`ALTER DATABASE SET DBPROPERTIES` statement changes the properties associated
with a database.
The specified property values override any existing value with the same
property name.
This command is mostly used to record the metadata for a database and may be
used for auditing purposes.
@@ -43,7 +43,25 @@ ALTER { DATABASE | SCHEMA | NAMESPACE } database_name
Specifies the name of the database to be altered.
-### ALTER LOCATION
+### UNSET PROPERTIES
+`ALTER DATABASE UNSET DBPROPERTIES` statement unsets the properties associated
with a database.
+If the specified property key does not exist, the command will ignore it and
finally succeed.
+(available since Spark 4.0.0).
+
+#### Syntax
+
+```sql
+ALTER { DATABASE | SCHEMA | NAMESPACE } database_name
+ UNSET { DBPROPERTIES | PROPERTIES } ( property_name [ , ... ] )
+```
+
+#### Parameters
+
+* **database_name**
+
+ Specifies the name of the database to be altered.
+
+### SET LOCATION
`ALTER DATABASE SET LOCATION` statement changes the default parent-directory
where new tables will be added
for a database. Please note that it does not move the contents of the
database's current directory to the newly
specified location or change the locations associated with any
tables/partitions under the specified database
@@ -95,6 +113,24 @@ DESCRIBE DATABASE EXTENDED inventory;
| Location|file:/temp/spark-warehouse/new_inventory.db|
| Properties| ((Edit-date,01/01/2001), (Edited-by,John))|
+-------------------------+-------------------------------------------+
+
+-- Alters the database to unset the property `Edited-by`
+ALTER DATABASE inventory UNSET DBPROPERTIES ('Edited-by');
+
+-- Verify that the property `Edited-by` has been unset.
+DESCRIBE DATABASE EXTENDED inventory;
++-------------------------+-------------------------------------------+
+|database_description_item| database_description_value|
++-------------------------+-------------------------------------------+
+| Database Name| inventory|
+| Description| |
+| Location|file:/temp/spark-warehouse/new_inventory.db|
+| Properties| ((Edit-date,01/01/2001)) |
++-------------------------+-------------------------------------------+
+
+-- Alters the database to unset a non-existent property `non-existent`
+-- Note: The command will ignore 'non-existent' and finally succeed
+ALTER DATABASE inventory UNSET DBPROPERTIES ('non-existent');
```
### Related Statements
diff --git
a/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4
b/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4
index ff863565910d..54eff14b6d4d 100644
---
a/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4
+++
b/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4
@@ -105,6 +105,8 @@ statement
(WITH (DBPROPERTIES | PROPERTIES) propertyList))*
#createNamespace
| ALTER namespace identifierReference
SET (DBPROPERTIES | PROPERTIES) propertyList
#setNamespaceProperties
+ | ALTER namespace identifierReference
+ UNSET (DBPROPERTIES | PROPERTIES) propertyList
#unsetNamespaceProperties
| ALTER namespace identifierReference
SET locationSpec
#setNamespaceLocation
| DROP namespace (IF EXISTS)? identifierReference
diff --git
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala
index bca2c8725394..dc43bd163659 100644
---
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala
+++
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala
@@ -3671,7 +3671,7 @@ class AstBuilder extends DataTypeAstBuilder with
SQLConfHelper with Logging {
}
}
- private def cleanNamespaceProperties(
+ protected def cleanNamespaceProperties(
properties: Map[String, String],
ctx: ParserRuleContext): Map[String, String] = withOrigin(ctx) {
import SupportsNamespaces._
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 59169dc51415..055fec02d2ae 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
@@ -27,7 +27,7 @@ import org.antlr.v4.runtime.tree.TerminalNode
import org.apache.spark.SparkException
import org.apache.spark.sql.catalyst.{FunctionIdentifier, TableIdentifier}
-import org.apache.spark.sql.catalyst.analysis.{GlobalTempView, LocalTempView,
PersistedView, SchemaEvolution, SchemaTypeEvolution, UnresolvedFunctionName,
UnresolvedIdentifier}
+import org.apache.spark.sql.catalyst.analysis.{GlobalTempView, LocalTempView,
PersistedView, SchemaEvolution, SchemaTypeEvolution, UnresolvedFunctionName,
UnresolvedIdentifier, UnresolvedNamespace}
import org.apache.spark.sql.catalyst.catalog._
import org.apache.spark.sql.catalyst.expressions.{Expression, Literal}
import org.apache.spark.sql.catalyst.parser._
@@ -1098,4 +1098,22 @@ class SparkSqlAstBuilder extends AstBuilder {
(ctx.LOCAL != null, finalStorage, Some(DDLUtils.HIVE_PROVIDER))
}
+
+ /**
+ * Create a [[UnsetNamespacePropertiesCommand]] command.
+ *
+ * Expected format:
+ * {{{
+ * ALTER (DATABASE|SCHEMA|NAMESPACE) database
+ * UNSET (DBPROPERTIES | PROPERTIES) ('key1', 'key2');
+ * }}}
+ */
+ override def visitUnsetNamespaceProperties(
+ ctx: UnsetNamespacePropertiesContext): LogicalPlan = withOrigin(ctx) {
+ val properties = visitPropertyKeys(ctx.propertyList)
+ val cleanedProperties = cleanNamespaceProperties(properties.map(_ ->
"").toMap, ctx).keys.toSeq
+ UnsetNamespacePropertiesCommand(
+ withIdentClause(ctx.identifierReference(), UnresolvedNamespace(_)),
+ cleanedProperties)
+ }
}
diff --git
a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/UnsetNamespacePropertiesCommand.scala
b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/UnsetNamespacePropertiesCommand.scala
new file mode 100644
index 000000000000..243b51b09e3b
--- /dev/null
+++
b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/UnsetNamespacePropertiesCommand.scala
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.spark.sql.execution.command
+
+import org.apache.spark.sql.{Row, SparkSession}
+import org.apache.spark.sql.catalyst.analysis.ResolvedNamespace
+import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan
+import org.apache.spark.sql.connector.catalog.CatalogV2Implicits.CatalogHelper
+import org.apache.spark.sql.connector.catalog.NamespaceChange
+
+/**
+ * A command that unsets database/schema/namespace properties.
+ *
+ * The syntax of this command is:
+ * {{{
+ * ALTER (DATABASE|SCHEMA|NAMESPACE) ...
+ * UNSET (DBPROPERTIES|PROPERTIES) ('key1', 'key2', ...);
+ * }}}
+ */
+case class UnsetNamespacePropertiesCommand(
+ ident: LogicalPlan,
+ propKeys: Seq[String]) extends UnaryRunnableCommand {
+
+ override def run(sparkSession: SparkSession): Seq[Row] = {
+ val ResolvedNamespace(catalog, ns, _) = child
+ val changes = propKeys.map {
+ NamespaceChange.removeProperty
+ }
+ // If the property does not exist, the change should succeed.
+ catalog.asNamespaceCatalog.alterNamespace(ns.toArray, changes: _*)
+
+ Seq.empty
+ }
+
+ override def child: LogicalPlan = ident
+
+ override protected def withNewChildInternal(
+ newChild: LogicalPlan): UnsetNamespacePropertiesCommand =
+ copy(ident = newChild)
+}
diff --git
a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/commands.scala
b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/commands.scala
index eec79ad02e29..ea2736b2c126 100644
---
a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/commands.scala
+++
b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/commands.scala
@@ -26,7 +26,7 @@ import org.apache.spark.sql.catalyst.{CatalystTypeConverters,
InternalRow}
import org.apache.spark.sql.catalyst.expressions.{Attribute,
AttributeReference}
import org.apache.spark.sql.catalyst.plans.QueryPlan
import org.apache.spark.sql.catalyst.plans.logical.{Command, LogicalPlan,
SupervisingCommand}
-import org.apache.spark.sql.catalyst.trees.LeafLike
+import org.apache.spark.sql.catalyst.trees.{LeafLike, UnaryLike}
import org.apache.spark.sql.connector.ExternalCommandRunner
import org.apache.spark.sql.execution.{CommandExecutionMode, ExplainMode,
LeafExecNode, SparkPlan, UnaryExecNode}
import org.apache.spark.sql.execution.metric.SQLMetric
@@ -51,6 +51,7 @@ trait RunnableCommand extends Command {
}
trait LeafRunnableCommand extends RunnableCommand with LeafLike[LogicalPlan]
+trait UnaryRunnableCommand extends RunnableCommand with UnaryLike[LogicalPlan]
/**
* A physical operator that executes the run method of a `RunnableCommand` and
diff --git
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/AlterNamespaceSetPropertiesSuiteBase.scala
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/AlterNamespaceSetPropertiesSuiteBase.scala
index c28c7b9db043..7f5b3de4865c 100644
---
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/AlterNamespaceSetPropertiesSuiteBase.scala
+++
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/AlterNamespaceSetPropertiesSuiteBase.scala
@@ -83,10 +83,19 @@ trait AlterNamespaceSetPropertiesSuiteBase extends
QueryTest with DDLCommandTest
CatalogV2Util.NAMESPACE_RESERVED_PROPERTIES.filterNot(_ ==
PROP_COMMENT).foreach { key =>
withNamespace(ns) {
sql(s"CREATE NAMESPACE $ns")
- val exception = intercept[ParseException] {
- sql(s"ALTER NAMESPACE $ns SET PROPERTIES ('$key'='dummyVal')")
- }
- assert(exception.getMessage.contains(s"$key is a reserved namespace
property"))
+ val sqlText = s"ALTER NAMESPACE $ns SET PROPERTIES
('$key'='dummyVal')"
+ checkErrorMatchPVals(
+ exception = intercept[ParseException] {
+ sql(sqlText)
+ },
+ errorClass = "UNSUPPORTED_FEATURE.SET_NAMESPACE_PROPERTY",
+ parameters = Map("property" -> key, "msg" -> ".*"),
+ sqlState = None,
+ context = ExpectedContext(
+ fragment = sqlText,
+ start = 0,
+ stop = 46 + ns.length + key.length)
+ )
}
}
}
diff --git
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/AlterNamespaceUnsetPropertiesParserSuite.scala
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/AlterNamespaceUnsetPropertiesParserSuite.scala
new file mode 100644
index 000000000000..72d307c81666
--- /dev/null
+++
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/AlterNamespaceUnsetPropertiesParserSuite.scala
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.spark.sql.execution.command
+
+import org.apache.spark.SparkThrowable
+import org.apache.spark.sql.catalyst.analysis.{AnalysisTest,
UnresolvedNamespace}
+import org.apache.spark.sql.catalyst.parser.ParseException
+import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan
+import org.apache.spark.sql.execution.SparkSqlParser
+import org.apache.spark.sql.test.SharedSparkSession
+
+class AlterNamespaceUnsetPropertiesParserSuite extends AnalysisTest with
SharedSparkSession {
+
+ private lazy val parser = new SparkSqlParser()
+
+ private def parseException(sqlText: String): SparkThrowable = {
+ intercept[ParseException](sql(sqlText).collect())
+ }
+
+ private def parsePlan(sqlText: String): LogicalPlan = {
+ parser.parsePlan(sqlText)
+ }
+
+ test("unset namespace properties") {
+ Seq("DATABASE", "SCHEMA", "NAMESPACE").foreach { nsToken =>
+ Seq("PROPERTIES", "DBPROPERTIES").foreach { propToken =>
+ comparePlans(
+ parsePlan(s"ALTER $nsToken a.b.c UNSET $propToken ('a', 'b', 'c')"),
+ UnsetNamespacePropertiesCommand(
+ UnresolvedNamespace(Seq("a", "b", "c")), Seq("a", "b", "c")))
+
+ comparePlans(
+ parsePlan(s"ALTER $nsToken a.b.c UNSET $propToken ('a')"),
+ UnsetNamespacePropertiesCommand(UnresolvedNamespace(Seq("a", "b",
"c")), Seq("a")))
+ }
+ }
+ }
+
+ test("property values must not be set") {
+ val sql = "ALTER NAMESPACE my_db UNSET PROPERTIES('key_without_value',
'key_with_value'='x')"
+ checkError(
+ exception = parseException(sql),
+ errorClass = "_LEGACY_ERROR_TEMP_0035",
+ parameters = Map("message" -> "Values should not be specified for
key(s): [key_with_value]"),
+ context = ExpectedContext(
+ fragment = sql,
+ start = 0,
+ stop = 80))
+ }
+
+ test("not support clause - IF EXISTS") {
+ Seq("DATABASE", "SCHEMA", "NAMESPACE").foreach { nsToken =>
+ Seq("PROPERTIES", "DBPROPERTIES").foreach { propToken =>
+ val sql = s"ALTER $nsToken a.b.c UNSET $propToken IF EXISTS ('a', 'b',
'c')"
+ checkError(
+ exception = parseException(sql),
+ errorClass = "PARSE_SYNTAX_ERROR",
+ parameters = Map("error" -> "'IF'", "hint" -> ": missing '('")
+ )
+ }
+ }
+ }
+}
diff --git
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/AlterNamespaceSetPropertiesSuiteBase.scala
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/AlterNamespaceUnsetPropertiesSuiteBase.scala
similarity index 71%
copy from
sql/core/src/test/scala/org/apache/spark/sql/execution/command/AlterNamespaceSetPropertiesSuiteBase.scala
copy to
sql/core/src/test/scala/org/apache/spark/sql/execution/command/AlterNamespaceUnsetPropertiesSuiteBase.scala
index c28c7b9db043..1d43cc593848 100644
---
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/AlterNamespaceSetPropertiesSuiteBase.scala
+++
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/AlterNamespaceUnsetPropertiesSuiteBase.scala
@@ -23,30 +23,37 @@ import
org.apache.spark.sql.connector.catalog.{CatalogV2Util, SupportsNamespaces
import org.apache.spark.sql.internal.SQLConf
/**
- * This base suite contains unified tests for the `ALTER NAMESPACE ... SET
PROPERTIES` command that
- * check V1 and V2 table catalogs. The tests that cannot run for all supported
catalogs are located
- * in more specific test suites:
+ * This base suite contains unified tests for the `ALTER NAMESPACE ... UNSET
PROPERTIES` command
+ * that check V1 and V2 table catalogs. The tests that cannot run for all
supported catalogs are
+ * located in more specific test suites:
*
* - V2 table catalog tests:
- *
`org.apache.spark.sql.execution.command.v2.AlterNamespaceSetPropertiesSuite`
+ *
`org.apache.spark.sql.execution.command.v2.AlterNamespaceUnsetPropertiesSuite`
* - V1 table catalog tests:
- *
`org.apache.spark.sql.execution.command.v1.AlterNamespaceSetPropertiesSuiteBase`
+ *
`org.apache.spark.sql.execution.command.v1.AlterNamespaceUnsetPropertiesSuiteBase`
* - V1 In-Memory catalog:
- *
`org.apache.spark.sql.execution.command.v1.AlterNamespaceSetPropertiesSuite`
+ *
`org.apache.spark.sql.execution.command.v1.AlterNamespaceUnsetPropertiesSuite`
* - V1 Hive External catalog:
- *
`org.apache.spark.sql.hive.execution.command.AlterNamespaceSetPropertiesSuite`
+ *
`org.apache.spark.sql.hive.execution.command.AlterNamespaceUnsetPropertiesSuite`
*/
-trait AlterNamespaceSetPropertiesSuiteBase extends QueryTest with
DDLCommandTestUtils {
- override val command = "ALTER NAMESPACE ... SET PROPERTIES"
+trait AlterNamespaceUnsetPropertiesSuiteBase extends QueryTest with
DDLCommandTestUtils {
+ override val command = "ALTER NAMESPACE ... UNSET PROPERTIES"
protected def namespace: String
- protected def notFoundMsgPrefix: String
+ protected def getProperties(namespace: String): String = {
+ val propsRow = sql(s"DESCRIBE NAMESPACE EXTENDED $namespace")
+ .toDF("key", "value")
+ .where("key like 'Properties%'")
+ .collect()
+ assert(propsRow.length == 1)
+ propsRow(0).getString(1)
+ }
- test("Namespace does not exist") {
+ test("namespace does not exist") {
val ns = "not_exist"
val e = intercept[AnalysisException] {
- sql(s"ALTER DATABASE $catalog.$ns SET PROPERTIES ('d'='d')")
+ sql(s"ALTER NAMESPACE $catalog.$ns UNSET PROPERTIES ('d')")
}
checkError(e,
errorClass = "SCHEMA_NOT_FOUND",
@@ -60,18 +67,13 @@ trait AlterNamespaceSetPropertiesSuiteBase extends
QueryTest with DDLCommandTest
assert(getProperties(ns) === "")
sql(s"ALTER NAMESPACE $ns SET PROPERTIES ('a'='a', 'b'='b', 'c'='c')")
assert(getProperties(ns) === "((a,a), (b,b), (c,c))")
- sql(s"ALTER DATABASE $ns SET PROPERTIES ('d'='d')")
- assert(getProperties(ns) === "((a,a), (b,b), (c,c), (d,d))")
- }
- }
+ sql(s"ALTER NAMESPACE $ns UNSET PROPERTIES ('b')")
+ assert(getProperties(ns) === "((a,a), (c,c))")
- test("test with properties set while creating namespace") {
- val ns = s"$catalog.$namespace"
- withNamespace(ns) {
- sql(s"CREATE NAMESPACE $ns WITH PROPERTIES ('a'='a','b'='b','c'='c')")
- assert(getProperties(ns) === "((a,a), (b,b), (c,c))")
- sql(s"ALTER NAMESPACE $ns SET PROPERTIES ('a'='b', 'b'='a')")
- assert(getProperties(ns) === "((a,b), (b,a), (c,c))")
+ // unset non-existent properties
+ // it will be successful, ignoring non-existent properties
+ sql(s"ALTER NAMESPACE $ns UNSET PROPERTIES ('b')")
+ assert(getProperties(ns) === "((a,a), (c,c))")
}
}
@@ -83,10 +85,19 @@ trait AlterNamespaceSetPropertiesSuiteBase extends
QueryTest with DDLCommandTest
CatalogV2Util.NAMESPACE_RESERVED_PROPERTIES.filterNot(_ ==
PROP_COMMENT).foreach { key =>
withNamespace(ns) {
sql(s"CREATE NAMESPACE $ns")
- val exception = intercept[ParseException] {
- sql(s"ALTER NAMESPACE $ns SET PROPERTIES ('$key'='dummyVal')")
- }
- assert(exception.getMessage.contains(s"$key is a reserved namespace
property"))
+ val sqlText = s"ALTER NAMESPACE $ns UNSET PROPERTIES ('$key')"
+ checkErrorMatchPVals(
+ exception = intercept[ParseException] {
+ sql(sqlText)
+ },
+ errorClass = "UNSUPPORTED_FEATURE.SET_NAMESPACE_PROPERTY",
+ parameters = Map("property" -> key, "msg" -> ".*"),
+ sqlState = None,
+ context = ExpectedContext(
+ fragment = sqlText,
+ start = 0,
+ stop = 37 + ns.length + key.length)
+ )
}
}
}
@@ -97,7 +108,7 @@ trait AlterNamespaceSetPropertiesSuiteBase extends QueryTest
with DDLCommandTest
// Without this, `meta.get(key)` below may return null.
sql(s"CREATE NAMESPACE $ns LOCATION 'tmp/prop_test'")
assert(getProperties(ns) === "")
- sql(s"ALTER NAMESPACE $ns SET PROPERTIES ('$key'='foo')")
+ sql(s"ALTER NAMESPACE $ns UNSET PROPERTIES ('$key')")
assert(getProperties(ns) === "", s"$key is a reserved namespace
property and ignored")
val meta = spark.sessionState.catalogManager.catalog(catalog)
.asNamespaceCatalog.loadNamespaceMetadata(namespace.split('.'))
@@ -107,13 +118,4 @@ trait AlterNamespaceSetPropertiesSuiteBase extends
QueryTest with DDLCommandTest
}
}
}
-
- protected def getProperties(namespace: String): String = {
- val propsRow = sql(s"DESCRIBE NAMESPACE EXTENDED $namespace")
- .toDF("key", "value")
- .where("key like 'Properties%'")
- .collect()
- assert(propsRow.length == 1)
- propsRow(0).getString(1)
- }
}
diff --git
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v1/AlterNamespaceUnsetPropertiesSuiteBase.scala
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v1/AlterNamespaceUnsetPropertiesSuiteBase.scala
new file mode 100644
index 000000000000..da7fdbba16b0
--- /dev/null
+++
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v1/AlterNamespaceUnsetPropertiesSuiteBase.scala
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.spark.sql.execution.command.v1
+
+import org.apache.spark.sql.execution.command
+
+/**
+ * This base suite contains unified tests for the `ALTER NAMESPACE ... UNSET
PROPERTIES` command
+ * that checks V1 table catalogs. The tests that cannot run for all V1
catalogs are located in more
+ * specific test suites:
+ *
+ * - V1 In-Memory catalog:
+ *
`org.apache.spark.sql.execution.command.v1.AlterNamespaceUnsetPropertiesSuite`
+ * - V1 Hive External catalog:
+ *
`org.apache.spark.sql.hive.execution.command.AlterNamespaceUnsetPropertiesSuite`
+ */
+trait AlterNamespaceUnsetPropertiesSuiteBase extends
command.AlterNamespaceUnsetPropertiesSuiteBase
+ with command.TestsV1AndV2Commands {
+ override def namespace: String = "db"
+}
+
+/**
+ * The class contains tests for the `ALTER NAMESPACE ... UNSET PROPERTIES`
command to
+ * check V1 In-Memory table catalog.
+ */
+class AlterNamespaceUnsetPropertiesSuite extends
AlterNamespaceUnsetPropertiesSuiteBase
+ with CommandSuiteBase {
+ override def commandVersion: String =
+ super[AlterNamespaceUnsetPropertiesSuiteBase].commandVersion
+}
diff --git
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v2/AlterNamespaceUnsetPropertiesSuite.scala
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v2/AlterNamespaceUnsetPropertiesSuite.scala
new file mode 100644
index 000000000000..352238eda2ea
--- /dev/null
+++
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v2/AlterNamespaceUnsetPropertiesSuite.scala
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.spark.sql.execution.command.v2
+
+import org.apache.spark.sql.execution.command
+
+/**
+ * The class contains tests for the `ALTER NAMESPACE ... UNSET PROPERTIES`
command to check V2
+ * table catalogs.
+ */
+class AlterNamespaceUnsetPropertiesSuite extends
command.AlterNamespaceUnsetPropertiesSuiteBase
+ with CommandSuiteBase {
+
+ override def namespace: String = "ns1.ns2"
+}
diff --git
a/sql/hive/src/test/scala/org/apache/spark/sql/hive/execution/command/AlterNamespaceUnsetPropertiesSuite.scala
b/sql/hive/src/test/scala/org/apache/spark/sql/hive/execution/command/AlterNamespaceUnsetPropertiesSuite.scala
new file mode 100644
index 000000000000..22d833649fc6
--- /dev/null
+++
b/sql/hive/src/test/scala/org/apache/spark/sql/hive/execution/command/AlterNamespaceUnsetPropertiesSuite.scala
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.spark.sql.hive.execution.command
+
+import org.apache.spark.sql.execution.command.v1
+
+/**
+ * The class contains tests for the `ALTER NAMESPACE ... UNSET PROPERTIES`
command to check
+ * V1 Hive external table catalog.
+ */
+class AlterNamespaceUnsetPropertiesSuite extends
v1.AlterNamespaceUnsetPropertiesSuiteBase
+ with CommandSuiteBase {
+ override def commandVersion: String =
super[AlterNamespaceUnsetPropertiesSuiteBase].commandVersion
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]