From a01b6a92b5f0287a5236bddb1b817d13f320d489 Mon Sep 17 00:00:00 2001 From: gatorsmile <gatorsmile@gmail.com> Date: Sat, 26 Mar 2016 20:12:30 -0700 Subject: [PATCH] [SPARK-14177][SQL] Native Parsing for DDL Command "Describe Database" and "Alter Database" #### What changes were proposed in this pull request? This PR is to provide native parsing support for two DDL commands: ```Describe Database``` and ```Alter Database Set Properties``` Based on the Hive DDL document: https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL ##### 1. ALTER DATABASE **Syntax:** ```SQL ALTER (DATABASE|SCHEMA) database_name SET DBPROPERTIES (property_name=property_value, ...) ``` - `ALTER DATABASE` is to add new (key, value) pairs into `DBPROPERTIES` ##### 2. DESCRIBE DATABASE **Syntax:** ```SQL DESCRIBE DATABASE [EXTENDED] db_name ``` - `DESCRIBE DATABASE` shows the name of the database, its comment (if one has been set), and its root location on the filesystem. When `extended` is true, it also shows the database's properties #### How was this patch tested? Added the related test cases to `DDLCommandSuite` Author: gatorsmile <gatorsmile@gmail.com> Author: xiaoli <lixiao1983@gmail.com> Author: Xiao Li <xiaoli@Xiaos-MacBook-Pro.local> This patch had conflicts when merged, resolved by Committer: Yin Huai <yhuai@databricks.com> Closes #11977 from gatorsmile/parseAlterDatabase. --- .../apache/spark/sql/execution/SparkQl.scala | 27 +++++++++++++ .../spark/sql/execution/command/ddl.scala | 15 ++++++++ .../execution/command/DDLCommandSuite.scala | 38 +++++++++++++++++++ .../org/apache/spark/sql/hive/HiveQl.scala | 3 -- 4 files changed, 80 insertions(+), 3 deletions(-) diff --git a/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkQl.scala b/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkQl.scala index c78b9b429c..d4d1992d27 100644 --- a/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkQl.scala +++ b/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkQl.scala @@ -142,6 +142,33 @@ private[sql] class SparkQl(conf: ParserConf = SimpleParserConf()) extends Cataly "TOK_IFEXISTS", "TOK_RESTRICT", "TOK_CASCADE"), otherArgs) DropDatabase(databaseName, ifExists.isDefined, restrict = cascade.isEmpty)(node.source) + // ALTER (DATABASE|SCHEMA) database_name SET DBPROPERTIES (property_name=property_value, ...) + case Token("TOK_ALTERDATABASE_PROPERTIES", Token(dbName, Nil) :: args) => + val databaseName = unquoteString(dbName) + val dbprops = getClause("TOK_DATABASEPROPERTIES", args) + val props = dbprops match { + case Token("TOK_DATABASEPROPERTIES", Token("TOK_DBPROPLIST", propList) :: Nil) => + // Example format: + // + // TOK_DATABASEPROPERTIES + // +- TOK_DBPROPLIST + // :- TOK_TABLEPROPERTY + // : :- 'k1' + // : +- 'v1' + // :- TOK_TABLEPROPERTY + // :- 'k2' + // +- 'v2' + extractProps(propList, "TOK_TABLEPROPERTY") + case _ => parseFailed("Invalid ALTER DATABASE command", node) + } + AlterDatabaseProperties(databaseName, props.toMap)(node.source) + + // DESCRIBE DATABASE [EXTENDED] db_name + case Token("TOK_DESCDATABASE", Token(dbName, Nil) :: describeArgs) => + val databaseName = unquoteString(dbName) + val extended = getClauseOption("EXTENDED", describeArgs) + DescribeDatabase(databaseName, extended.isDefined)(node.source) + // CREATE [TEMPORARY] FUNCTION [db_name.]function_name AS class_name // [USING JAR|FILE|ARCHIVE 'file_uri' [, JAR|FILE|ARCHIVE 'file_uri'] ]; case Token("TOK_CREATEFUNCTION", args) => diff --git a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/ddl.scala b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/ddl.scala index a0f5b75284..0e51abb44b 100644 --- a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/ddl.scala +++ b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/ddl.scala @@ -71,6 +71,21 @@ case class DropDatabase( restrict: Boolean)(sql: String) extends NativeDDLCommand(sql) with Logging +/** ALTER DATABASE: add new (key, value) pairs into DBPROPERTIES */ +case class AlterDatabaseProperties( + databaseName: String, + props: Map[String, String])(sql: String) + extends NativeDDLCommand(sql) with Logging + +/** + * DESCRIBE DATABASE: shows the name of the database, its comment (if one has been set), and its + * root location on the filesystem. When extended is true, it also shows the database's properties + */ +case class DescribeDatabase( + databaseName: String, + extended: Boolean)(sql: String) + extends NativeDDLCommand(sql) with Logging + case class CreateFunction( databaseName: Option[String], functionName: String, diff --git a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLCommandSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLCommandSuite.scala index 18f48ffa94..7a6343748b 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLCommandSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLCommandSuite.scala @@ -101,6 +101,44 @@ class DDLCommandSuite extends PlanTest { comparePlans(parsed7, expected7) } + test("alter database set dbproperties") { + // ALTER (DATABASE|SCHEMA) database_name SET DBPROPERTIES (property_name=property_value, ...) + val sql1 = "ALTER DATABASE database_name SET DBPROPERTIES ('a'='a', 'b'='b', 'c'='c')" + val sql2 = "ALTER SCHEMA database_name SET DBPROPERTIES ('a'='a')" + + val parsed1 = parser.parsePlan(sql1) + val parsed2 = parser.parsePlan(sql2) + + val expected1 = AlterDatabaseProperties( + "database_name", + Map("a" -> "a", "b" -> "b", "c" -> "c"))(sql1) + val expected2 = AlterDatabaseProperties( + "database_name", + Map("a" -> "a"))(sql2) + + comparePlans(parsed1, expected1) + comparePlans(parsed2, expected2) + } + + test("describe database") { + // DESCRIBE DATABASE [EXTENDED] db_name; + val sql1 = "DESCRIBE DATABASE EXTENDED db_name" + val sql2 = "DESCRIBE DATABASE db_name" + + val parsed1 = parser.parsePlan(sql1) + val parsed2 = parser.parsePlan(sql2) + + val expected1 = DescribeDatabase( + "db_name", + extended = true)(sql1) + val expected2 = DescribeDatabase( + "db_name", + extended = false)(sql2) + + comparePlans(parsed1, expected1) + comparePlans(parsed2, expected2) + } + test("create function") { val sql1 = """ diff --git a/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveQl.scala b/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveQl.scala index 61fe0985c1..e5bcb9b1db 100644 --- a/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveQl.scala +++ b/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveQl.scala @@ -85,7 +85,6 @@ private[hive] class HiveQl(conf: ParserConf) extends SparkQl(conf) with Logging protected val nativeCommands = Seq( "TOK_ALTERDATABASE_OWNER", - "TOK_ALTERDATABASE_PROPERTIES", "TOK_ALTERINDEX_PROPERTIES", "TOK_ALTERINDEX_REBUILD", "TOK_ALTERTABLE_ALTERPARTS", @@ -100,8 +99,6 @@ private[hive] class HiveQl(conf: ParserConf) extends SparkQl(conf) with Logging "TOK_CREATEMACRO", "TOK_CREATEROLE", - "TOK_DESCDATABASE", - "TOK_DROPINDEX", "TOK_DROPMACRO", "TOK_DROPROLE", -- GitLab