aboutsummaryrefslogtreecommitdiff
path: root/sql/catalyst
diff options
context:
space:
mode:
authorXiao Li <gatorsmile@gmail.com>2017-04-03 23:30:12 -0700
committerXiao Li <gatorsmile@gmail.com>2017-04-03 23:30:12 -0700
commit51d3c854c54369aec1bfd55cefcd080dcd178d5f (patch)
tree8c83dc8698f16b4af724fe4f8a1a7901224bdffb /sql/catalyst
parent3bfb639cb7352aec572ef6686d3471bd78748ffa (diff)
downloadspark-51d3c854c54369aec1bfd55cefcd080dcd178d5f.tar.gz
spark-51d3c854c54369aec1bfd55cefcd080dcd178d5f.tar.bz2
spark-51d3c854c54369aec1bfd55cefcd080dcd178d5f.zip
[SPARK-20067][SQL] Unify and Clean Up Desc Commands Using Catalog Interface
### What changes were proposed in this pull request? This PR is to unify and clean up the outputs of `DESC EXTENDED/FORMATTED` and `SHOW TABLE EXTENDED` by moving the logics into the Catalog interface. The output formats are improved. We also add the missing attributes. It impacts the DDL commands like `SHOW TABLE EXTENDED`, `DESC EXTENDED` and `DESC FORMATTED`. In addition, by following what we did in Dataset API `printSchema`, we can use `treeString` to show the schema in the more readable way. Below is the current way: ``` Schema: STRUCT<`a`: STRING (nullable = true), `b`: INT (nullable = true), `c`: STRING (nullable = true), `d`: STRING (nullable = true)> ``` After the change, it should look like ``` Schema: root |-- a: string (nullable = true) |-- b: integer (nullable = true) |-- c: string (nullable = true) |-- d: string (nullable = true) ``` ### How was this patch tested? `describe.sql` and `show-tables.sql` Author: Xiao Li <gatorsmile@gmail.com> Closes #17394 from gatorsmile/descFollowUp.
Diffstat (limited to 'sql/catalyst')
-rw-r--r--sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/catalog/interface.scala136
1 files changed, 87 insertions, 49 deletions
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 70ed44e025..3f25f9e725 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
@@ -20,6 +20,8 @@ package org.apache.spark.sql.catalyst.catalog
import java.net.URI
import java.util.Date
+import scala.collection.mutable
+
import com.google.common.base.Objects
import org.apache.spark.sql.AnalysisException
@@ -57,20 +59,25 @@ case class CatalogStorageFormat(
properties: Map[String, String]) {
override def toString: String = {
- val serdePropsToString = CatalogUtils.maskCredentials(properties) match {
- case props if props.isEmpty => ""
- case props => "Properties: " + props.map(p => p._1 + "=" + p._2).mkString("[", ", ", "]")
- }
- val output =
- Seq(locationUri.map("Location: " + _).getOrElse(""),
- inputFormat.map("InputFormat: " + _).getOrElse(""),
- outputFormat.map("OutputFormat: " + _).getOrElse(""),
- if (compressed) "Compressed" else "",
- serde.map("Serde: " + _).getOrElse(""),
- serdePropsToString)
- output.filter(_.nonEmpty).mkString("Storage(", ", ", ")")
+ toLinkedHashMap.map { case ((key, value)) =>
+ if (value.isEmpty) key else s"$key: $value"
+ }.mkString("Storage(", ", ", ")")
}
+ def toLinkedHashMap: mutable.LinkedHashMap[String, String] = {
+ val map = new mutable.LinkedHashMap[String, String]()
+ locationUri.foreach(l => map.put("Location", l.toString))
+ serde.foreach(map.put("Serde Library", _))
+ inputFormat.foreach(map.put("InputFormat", _))
+ outputFormat.foreach(map.put("OutputFormat", _))
+ if (compressed) map.put("Compressed", "")
+ CatalogUtils.maskCredentials(properties) match {
+ case props if props.isEmpty => // No-op
+ case props =>
+ map.put("Properties", props.map(p => p._1 + "=" + p._2).mkString("[", ", ", "]"))
+ }
+ map
+ }
}
object CatalogStorageFormat {
@@ -91,15 +98,28 @@ case class CatalogTablePartition(
storage: CatalogStorageFormat,
parameters: Map[String, String] = Map.empty) {
- override def toString: String = {
+ def toLinkedHashMap: mutable.LinkedHashMap[String, String] = {
+ val map = new mutable.LinkedHashMap[String, String]()
val specString = spec.map { case (k, v) => s"$k=$v" }.mkString(", ")
- val output =
- Seq(
- s"Partition Values: [$specString]",
- s"$storage",
- s"Partition Parameters:{${parameters.map(p => p._1 + "=" + p._2).mkString(", ")}}")
+ map.put("Partition Values", s"[$specString]")
+ map ++= storage.toLinkedHashMap
+ if (parameters.nonEmpty) {
+ map.put("Partition Parameters", s"{${parameters.map(p => p._1 + "=" + p._2).mkString(", ")}}")
+ }
+ map
+ }
- output.filter(_.nonEmpty).mkString("CatalogPartition(\n\t", "\n\t", ")")
+ override def toString: String = {
+ toLinkedHashMap.map { case ((key, value)) =>
+ if (value.isEmpty) key else s"$key: $value"
+ }.mkString("CatalogPartition(\n\t", "\n\t", ")")
+ }
+
+ /** Readable string representation for the CatalogTablePartition. */
+ def simpleString: String = {
+ toLinkedHashMap.map { case ((key, value)) =>
+ if (value.isEmpty) key else s"$key: $value"
+ }.mkString("", "\n", "")
}
/** Return the partition location, assuming it is specified. */
@@ -154,6 +174,14 @@ case class BucketSpec(
}
s"$numBuckets buckets, $bucketString$sortString"
}
+
+ def toLinkedHashMap: mutable.LinkedHashMap[String, String] = {
+ mutable.LinkedHashMap[String, String](
+ "Num Buckets" -> numBuckets.toString,
+ "Bucket Columns" -> bucketColumnNames.map(quoteIdentifier).mkString("[", ", ", "]"),
+ "Sort Columns" -> sortColumnNames.map(quoteIdentifier).mkString("[", ", ", "]")
+ )
+ }
}
/**
@@ -261,40 +289,50 @@ case class CatalogTable(
locationUri, inputFormat, outputFormat, serde, compressed, properties))
}
- override def toString: String = {
+
+ def toLinkedHashMap: mutable.LinkedHashMap[String, String] = {
+ val map = new mutable.LinkedHashMap[String, String]()
val tableProperties = properties.map(p => p._1 + "=" + p._2).mkString("[", ", ", "]")
val partitionColumns = partitionColumnNames.map(quoteIdentifier).mkString("[", ", ", "]")
- val bucketStrings = bucketSpec match {
- case Some(BucketSpec(numBuckets, bucketColumnNames, sortColumnNames)) =>
- val bucketColumnsString = bucketColumnNames.map(quoteIdentifier).mkString("[", ", ", "]")
- val sortColumnsString = sortColumnNames.map(quoteIdentifier).mkString("[", ", ", "]")
- Seq(
- s"Num Buckets: $numBuckets",
- if (bucketColumnNames.nonEmpty) s"Bucket Columns: $bucketColumnsString" else "",
- if (sortColumnNames.nonEmpty) s"Sort Columns: $sortColumnsString" else ""
- )
-
- case _ => Nil
+
+ identifier.database.foreach(map.put("Database", _))
+ map.put("Table", identifier.table)
+ if (owner.nonEmpty) map.put("Owner", owner)
+ map.put("Created", new Date(createTime).toString)
+ map.put("Last Access", new Date(lastAccessTime).toString)
+ map.put("Type", tableType.name)
+ provider.foreach(map.put("Provider", _))
+ bucketSpec.foreach(map ++= _.toLinkedHashMap)
+ comment.foreach(map.put("Comment", _))
+ if (tableType == CatalogTableType.VIEW) {
+ viewText.foreach(map.put("View Text", _))
+ viewDefaultDatabase.foreach(map.put("View Default Database", _))
+ if (viewQueryColumnNames.nonEmpty) {
+ map.put("View Query Output Columns", viewQueryColumnNames.mkString("[", ", ", "]"))
+ }
}
- val output =
- Seq(s"Table: ${identifier.quotedString}",
- if (owner.nonEmpty) s"Owner: $owner" else "",
- s"Created: ${new Date(createTime).toString}",
- s"Last Access: ${new Date(lastAccessTime).toString}",
- s"Type: ${tableType.name}",
- if (schema.nonEmpty) s"Schema: ${schema.mkString("[", ", ", "]")}" else "",
- if (provider.isDefined) s"Provider: ${provider.get}" else "",
- if (partitionColumnNames.nonEmpty) s"Partition Columns: $partitionColumns" else ""
- ) ++ bucketStrings ++ Seq(
- viewText.map("View: " + _).getOrElse(""),
- comment.map("Comment: " + _).getOrElse(""),
- if (properties.nonEmpty) s"Properties: $tableProperties" else "",
- if (stats.isDefined) s"Statistics: ${stats.get.simpleString}" else "",
- s"$storage",
- if (tracksPartitionsInCatalog) "Partition Provider: Catalog" else "")
-
- output.filter(_.nonEmpty).mkString("CatalogTable(\n\t", "\n\t", ")")
+ if (properties.nonEmpty) map.put("Properties", tableProperties)
+ stats.foreach(s => map.put("Statistics", s.simpleString))
+ map ++= storage.toLinkedHashMap
+ if (tracksPartitionsInCatalog) map.put("Partition Provider", "Catalog")
+ if (partitionColumnNames.nonEmpty) map.put("Partition Columns", partitionColumns)
+ if (schema.nonEmpty) map.put("Schema", schema.treeString)
+
+ map
+ }
+
+ override def toString: String = {
+ toLinkedHashMap.map { case ((key, value)) =>
+ if (value.isEmpty) key else s"$key: $value"
+ }.mkString("CatalogTable(\n", "\n", ")")
+ }
+
+ /** Readable string representation for the CatalogTable. */
+ def simpleString: String = {
+ toLinkedHashMap.map { case ((key, value)) =>
+ if (value.isEmpty) key else s"$key: $value"
+ }.mkString("", "\n", "")
}
}