diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/catalog/interface.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/catalog/interface.scala index 8011aceff3..d51690367b 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/catalog/interface.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/catalog/interface.scala @@ -388,12 +388,13 @@ case class CatalogTable( } object CatalogTable { + val VIEW_PREFIX = "view." // Starting from Spark 3.0, we don't use this property any more. `VIEW_CATALOG_AND_NAMESPACE` is // used instead. - val VIEW_DEFAULT_DATABASE = "view.default.database" + val VIEW_DEFAULT_DATABASE = VIEW_PREFIX + "default.database" - val VIEW_CATALOG_AND_NAMESPACE = "view.catalogAndNamespace.numParts" - val VIEW_CATALOG_AND_NAMESPACE_PART_PREFIX = "view.catalogAndNamespace.part." + val VIEW_CATALOG_AND_NAMESPACE = VIEW_PREFIX + "catalogAndNamespace.numParts" + val VIEW_CATALOG_AND_NAMESPACE_PART_PREFIX = VIEW_PREFIX + "catalogAndNamespace.part." // Convert the current catalog and namespace to properties. def catalogAndNamespaceToProps( currentCatalog: String, @@ -409,7 +410,7 @@ object CatalogTable { props.toMap } - val VIEW_QUERY_OUTPUT_PREFIX = "view.query.out." + val VIEW_QUERY_OUTPUT_PREFIX = VIEW_PREFIX + "query.out." val VIEW_QUERY_OUTPUT_NUM_COLUMNS = VIEW_QUERY_OUTPUT_PREFIX + "numCols" val VIEW_QUERY_OUTPUT_COLUMN_NAME_PREFIX = VIEW_QUERY_OUTPUT_PREFIX + "col." } diff --git a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/tables.scala b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/tables.scala index 8dc07b7b3c..6eb55d58d6 100644 --- a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/tables.scala +++ b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/tables.scala @@ -1014,13 +1014,13 @@ case class ShowCreateTableCommand(table: TableIdentifier) extends RunnableComman builder ++= s"CREATE$tableTypeString ${table.quotedString}" if (metadata.tableType == VIEW) { - if (metadata.schema.nonEmpty) { - builder ++= metadata.schema.map(_.name).mkString("(", ", ", ")") - } - builder ++= metadata.viewText.mkString(" AS\n", "", "\n") + showViewDataColumns(metadata, builder) + showComment(metadata, builder) + showViewProperties(metadata, builder) + showViewText(metadata, builder) } else { showHiveTableHeader(metadata, builder) - showTableComment(metadata, builder) + showComment(metadata, builder) showHiveTableNonDataColumns(metadata, builder) showHiveTableStorageInfo(metadata, builder) showTableLocation(metadata, builder) @@ -1030,6 +1030,35 @@ case class ShowCreateTableCommand(table: TableIdentifier) extends RunnableComman builder.toString() } + private def showViewDataColumns(metadata: CatalogTable, builder: StringBuilder): Unit = { + if (metadata.schema.nonEmpty) { + val viewColumns = metadata.schema.map { f => + val comment = f.getComment() + .map(escapeSingleQuotedString) + .map(" COMMENT '" + _ + "'") + + // view columns shouldn't have data type info + s"${quoteIdentifier(f.name)}${comment.getOrElse("")}" + } + builder ++= viewColumns.mkString("(", ", ", ")\n") + } + } + + private def showViewProperties(metadata: CatalogTable, builder: StringBuilder): Unit = { + val viewProps = metadata.properties.filterKeys(!_.startsWith(CatalogTable.VIEW_PREFIX)) + if (viewProps.nonEmpty) { + val props = viewProps.map { case (key, value) => + s"'${escapeSingleQuotedString(key)}' = '${escapeSingleQuotedString(value)}'" + } + + builder ++= props.mkString("TBLPROPERTIES (\n ", ",\n ", "\n)\n") + } + } + + private def showViewText(metadata: CatalogTable, builder: StringBuilder): Unit = { + builder ++= metadata.viewText.mkString("AS ", "", "\n") + } + private def showHiveTableHeader(metadata: CatalogTable, builder: StringBuilder): Unit = { val columns = metadata.schema.filterNot { column => metadata.partitionColumnNames.contains(column.name) @@ -1092,7 +1121,7 @@ case class ShowCreateTableCommand(table: TableIdentifier) extends RunnableComman } } - private def showTableComment(metadata: CatalogTable, builder: StringBuilder): Unit = { + private def showComment(metadata: CatalogTable, builder: StringBuilder): Unit = { metadata .comment .map("COMMENT '" + escapeSingleQuotedString(_) + "'\n") @@ -1116,7 +1145,7 @@ case class ShowCreateTableCommand(table: TableIdentifier) extends RunnableComman showDataSourceTableDataColumns(metadata, builder) showDataSourceTableOptions(metadata, builder) showDataSourceTableNonDataColumns(metadata, builder) - showTableComment(metadata, builder) + showComment(metadata, builder) showTableLocation(metadata, builder) showTableProperties(metadata, builder) diff --git a/sql/core/src/test/resources/sql-tests/inputs/show-create-table.sql b/sql/core/src/test/resources/sql-tests/inputs/show-create-table.sql index 3118371af3..ccb40f8d99 100644 --- a/sql/core/src/test/resources/sql-tests/inputs/show-create-table.sql +++ b/sql/core/src/test/resources/sql-tests/inputs/show-create-table.sql @@ -64,3 +64,34 @@ DROP TABLE tbl; CREATE TABLE tbl (a REAL, b NUMERIC, c NUMERIC(10), d NUMERIC(10,1)) USING parquet; SHOW CREATE TABLE tbl; DROP TABLE tbl; + + +-- show create table for view +CREATE TABLE tbl (a INT, b STRING, c INT) USING parquet; + +-- simple +CREATE VIEW view_SPARK_30302 (aaa, bbb) +AS SELECT a, b FROM tbl; + +SHOW CREATE TABLE view_SPARK_30302; +DROP VIEW view_SPARK_30302; + + +-- comment +CREATE VIEW view_SPARK_30302 (aaa COMMENT 'comment with \'quoted text\' for aaa', bbb) +COMMENT 'This is a comment with \'quoted text\' for view' +AS SELECT a, b FROM tbl; + +SHOW CREATE TABLE view_SPARK_30302; +DROP VIEW view_SPARK_30302; + + +-- tblproperties +CREATE VIEW view_SPARK_30302 (aaa, bbb) +TBLPROPERTIES ('a' = '1', 'b' = '2') +AS SELECT a, b FROM tbl; + +SHOW CREATE TABLE view_SPARK_30302; +DROP VIEW view_SPARK_30302; + +DROP TABLE tbl; diff --git a/sql/core/src/test/resources/sql-tests/results/show-create-table.sql.out b/sql/core/src/test/resources/sql-tests/results/show-create-table.sql.out index fc1b62ca61..2f973de329 100644 --- a/sql/core/src/test/resources/sql-tests/results/show-create-table.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/show-create-table.sql.out @@ -1,5 +1,5 @@ -- Automatically generated by SQLQueryTestSuite --- Number of queries: 27 +-- Number of queries: 38 -- !query 0 @@ -245,3 +245,104 @@ DROP TABLE tbl struct<> -- !query 26 output + + +-- !query 27 +CREATE TABLE tbl (a INT, b STRING, c INT) USING parquet +-- !query 27 schema +struct<> +-- !query 27 output + + + +-- !query 28 +CREATE VIEW view_SPARK_30302 (aaa, bbb) +AS SELECT a, b FROM tbl +-- !query 28 schema +struct<> +-- !query 28 output + + + +-- !query 29 +SHOW CREATE TABLE view_SPARK_30302 +-- !query 29 schema +struct +-- !query 29 output +CREATE VIEW `view_SPARK_30302`(`aaa`, `bbb`) +AS SELECT a, b FROM tbl + + +-- !query 30 +DROP VIEW view_SPARK_30302 +-- !query 30 schema +struct<> +-- !query 30 output + + + +-- !query 31 +CREATE VIEW view_SPARK_30302 (aaa COMMENT 'comment with \'quoted text\' for aaa', bbb) +COMMENT 'This is a comment with \'quoted text\' for view' +AS SELECT a, b FROM tbl +-- !query 31 schema +struct<> +-- !query 31 output + + + +-- !query 32 +SHOW CREATE TABLE view_SPARK_30302 +-- !query 32 schema +struct +-- !query 32 output +CREATE VIEW `view_SPARK_30302`(`aaa` COMMENT 'comment with \'quoted text\' for aaa', `bbb`) +COMMENT 'This is a comment with \'quoted text\' for view' +AS SELECT a, b FROM tbl + + +-- !query 33 +DROP VIEW view_SPARK_30302 +-- !query 33 schema +struct<> +-- !query 33 output + + + +-- !query 34 +CREATE VIEW view_SPARK_30302 (aaa, bbb) +TBLPROPERTIES ('a' = '1', 'b' = '2') +AS SELECT a, b FROM tbl +-- !query 34 schema +struct<> +-- !query 34 output + + + +-- !query 35 +SHOW CREATE TABLE view_SPARK_30302 +-- !query 35 schema +struct +-- !query 35 output +CREATE VIEW `view_SPARK_30302`(`aaa`, `bbb`) +TBLPROPERTIES ( + 'a' = '1', + 'b' = '2' +) +AS SELECT a, b FROM tbl + + +-- !query 36 +DROP VIEW view_SPARK_30302 +-- !query 36 schema +struct<> +-- !query 36 output + + + +-- !query 37 +DROP TABLE tbl +-- !query 37 schema +struct<> +-- !query 37 output +