Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -808,20 +808,10 @@ class Analyzer(
.map(v2Relation => i.copy(table = v2Relation))
.getOrElse(i)

case desc @ DescribeTable(u: UnresolvedV2Relation, _) =>
CatalogV2Util.loadRelation(u.catalog, u.tableName)
.map(rel => desc.copy(table = rel))
.getOrElse(desc)

case alter @ AlterTable(_, _, u: UnresolvedV2Relation, _) =>
CatalogV2Util.loadRelation(u.catalog, u.tableName)
.map(rel => alter.copy(table = rel))
.getOrElse(alter)

case show @ ShowTableProperties(u: UnresolvedV2Relation, _) =>
CatalogV2Util.loadRelation(u.catalog, u.tableName)
.map(rel => show.copy(table = rel))
.getOrElse(show)
.map(rel => alter.copy(table = rel))
.getOrElse(alter)

case u: UnresolvedV2Relation =>
CatalogV2Util.loadRelation(u.catalog, u.tableName).getOrElse(u)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,6 @@ trait CheckAnalysis extends PredicateHelper {
case AlterTable(_, _, u: UnresolvedV2Relation, _) =>
failAnalysis(s"Table not found: ${u.originalNameParts.quoted}")

case DescribeTable(u: UnresolvedV2Relation, _) if isView(u.originalNameParts) =>
u.failAnalysis(
s"Invalid command: '${u.originalNameParts.quoted}' is a view not a table.")

case DescribeTable(u: UnresolvedV2Relation, _) =>
failAnalysis(s"Table not found: ${u.originalNameParts.quoted}")

case operator: LogicalPlan =>
// Check argument data types of higher-order functions downwards first.
// If the arguments of the higher-order functions are resolved but the type check fails,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,6 @@ class ResolveCatalogs(val catalogManager: CatalogManager)
}
RenameTable(catalog.asTableCatalog, oldName.asIdentifier, newNameParts.asIdentifier)

case DescribeTableStatement(
nameParts @ NonSessionCatalogAndTable(catalog, tbl), partitionSpec, isExtended) =>
if (partitionSpec.nonEmpty) {
throw new AnalysisException("DESCRIBE TABLE does not support partition for v2 tables.")
}
val r = UnresolvedV2Relation(nameParts, catalog.asTableCatalog, tbl.asIdentifier)
DescribeTable(r, isExtended)

case DescribeColumnStatement(
NonSessionCatalogAndTable(catalog, tbl), colNameParts, isExtended) =>
throw new AnalysisException("Describing columns is not supported for v2 tables.")
Expand Down Expand Up @@ -196,11 +188,6 @@ class ResolveCatalogs(val catalogManager: CatalogManager)

case ShowCurrentNamespaceStatement() =>
ShowCurrentNamespace(catalogManager)

case ShowTablePropertiesStatement(
nameParts @ NonSessionCatalogAndTable(catalog, tbl), propertyKey) =>
val r = UnresolvedV2Relation(nameParts, catalog.asTableCatalog, tbl.asIdentifier)
ShowTableProperties(r, propertyKey)
}

object NonSessionCatalogAndTable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3024,7 +3024,7 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging
}

/**
* Create a [[DescribeColumnStatement]] or [[DescribeTableStatement]] commands.
* Create a [[DescribeColumnStatement]] or [[DescribeTable]] commands.
*/
override def visitDescribeTable(ctx: DescribeTableContext): LogicalPlan = withOrigin(ctx) {
val isExtended = ctx.EXTENDED != null || ctx.FORMATTED != null
Expand All @@ -3048,8 +3048,8 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging
} else {
Map.empty[String, String]
}
DescribeTableStatement(
visitMultipartIdentifier(ctx.multipartIdentifier()),
DescribeTable(
UnresolvedTable(visitMultipartIdentifier(ctx.multipartIdentifier())),
partitionSpec,
isExtended)
}
Expand Down Expand Up @@ -3427,8 +3427,8 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging
*/
override def visitShowTblProperties(
ctx: ShowTblPropertiesContext): LogicalPlan = withOrigin(ctx) {
ShowTablePropertiesStatement(
visitMultipartIdentifier(ctx.table),
ShowTableProperties(
UnresolvedTable(visitMultipartIdentifier(ctx.table)),
Option(ctx.key).map(visitTablePropertyKey))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,14 +290,6 @@ case class DropViewStatement(
viewName: Seq[String],
ifExists: Boolean) extends ParsedStatement

/**
* A DESCRIBE TABLE tbl_name statement, as parsed from SQL.
*/
case class DescribeTableStatement(
tableName: Seq[String],
partitionSpec: TablePartitionSpec,
isExtended: Boolean) extends ParsedStatement

/**
* A DESCRIBE TABLE tbl_name col_name statement, as parsed from SQL.
*/
Expand Down Expand Up @@ -444,13 +436,6 @@ case class ShowColumnsStatement(
*/
case class ShowCurrentNamespaceStatement() extends ParsedStatement

/**
* A SHOW TBLPROPERTIES statement, as parsed from SQL
*/
case class ShowTablePropertiesStatement(
tableName: Seq[String],
propertyKey: Option[String]) extends ParsedStatement

/**
* A DESCRIBE FUNCTION statement, as parsed from SQL
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.apache.spark.sql.catalyst.plans.logical

import org.apache.spark.sql.catalyst.analysis.{NamedRelation, UnresolvedException}
import org.apache.spark.sql.catalyst.catalog.CatalogTypes.TablePartitionSpec
import org.apache.spark.sql.catalyst.expressions.{Attribute, AttributeReference, Expression, Unevaluable}
import org.apache.spark.sql.catalyst.plans.DescribeTableSchema
import org.apache.spark.sql.connector.catalog._
Expand Down Expand Up @@ -306,10 +307,14 @@ case class ShowNamespaces(
/**
* The logical plan of the DESCRIBE TABLE command that works for v2 tables.
*/
case class DescribeTable(table: NamedRelation, isExtended: Boolean) extends Command {

case class DescribeTable(
table: LogicalPlan,
partitionSpec: TablePartitionSpec,
isExtended: Boolean) extends Command {
override lazy val resolved: Boolean = table.resolved

override def children: Seq[LogicalPlan] = table :: Nil

override def output: Seq[Attribute] = DescribeTableSchema.describeTableAttributes()
}

Expand Down Expand Up @@ -462,8 +467,10 @@ case class ShowCurrentNamespace(catalogManager: CatalogManager) extends Command
* The logical plan of the SHOW TBLPROPERTIES command that works for v2 catalogs.
*/
case class ShowTableProperties(
table: NamedRelation,
propertyKey: Option[String]) extends Command{
table: LogicalPlan,
propertyKey: Option[String]) extends Command {
override def children: Seq[LogicalPlan] = table :: Nil

override val output: Seq[Attribute] = Seq(
AttributeReference("key", StringType, nullable = false)(),
AttributeReference("value", StringType, nullable = false)())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -753,13 +753,13 @@ class DDLParserSuite extends AnalysisTest {

test("SPARK-17328 Fix NPE with EXPLAIN DESCRIBE TABLE") {
comparePlans(parsePlan("describe t"),
DescribeTableStatement(Seq("t"), Map.empty, isExtended = false))
DescribeTable(UnresolvedTable(Seq("t")), Map.empty, isExtended = false))
comparePlans(parsePlan("describe table t"),
DescribeTableStatement(Seq("t"), Map.empty, isExtended = false))
DescribeTable(UnresolvedTable(Seq("t")), Map.empty, isExtended = false))
comparePlans(parsePlan("describe table extended t"),
DescribeTableStatement(Seq("t"), Map.empty, isExtended = true))
DescribeTable(UnresolvedTable(Seq("t")), Map.empty, isExtended = true))
comparePlans(parsePlan("describe table formatted t"),
DescribeTableStatement(Seq("t"), Map.empty, isExtended = true))
DescribeTable(UnresolvedTable(Seq("t")), Map.empty, isExtended = true))
}

test("insert table: basic append") {
Expand Down Expand Up @@ -1861,11 +1861,11 @@ class DDLParserSuite extends AnalysisTest {
test("SHOW TBLPROPERTIES table") {
comparePlans(
parsePlan("SHOW TBLPROPERTIES a.b.c"),
ShowTablePropertiesStatement(Seq("a", "b", "c"), None))
ShowTableProperties(UnresolvedTable(Seq("a", "b", "c")), None))

comparePlans(
parsePlan("SHOW TBLPROPERTIES a.b.c('propKey1')"),
ShowTablePropertiesStatement(Seq("a", "b", "c"), Some("propKey1")))
ShowTableProperties(UnresolvedTable(Seq("a", "b", "c")), Some("propKey1")))
}

test("DESCRIBE FUNCTION") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,22 +201,21 @@ class ResolveSessionCatalog(
case RenameTableStatement(SessionCatalogAndTable(_, oldName), newNameParts, isView) =>
AlterTableRenameCommand(oldName.asTableIdentifier, newNameParts.asTableIdentifier, isView)

case DescribeTableStatement(
nameParts @ SessionCatalogAndTable(catalog, tbl), partitionSpec, isExtended) =>
loadTable(catalog, tbl.asIdentifier).collect {
case v1Table: V1Table =>
DescribeTableCommand(tbl.asTableIdentifier, partitionSpec, isExtended)
}.getOrElse {
// The v1 `DescribeTableCommand` can describe view as well.
if (isView(tbl)) {
DescribeTableCommand(tbl.asTableIdentifier, partitionSpec, isExtended)
} else {
if (partitionSpec.nonEmpty) {
throw new AnalysisException("DESCRIBE TABLE does not support partition for v2 tables.")
case d @ DescribeTable(SessionCatalogAndResolvedTable(resolved), partitionSpec, isExtended) =>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems simpler to write

d @ DescribeTable(r: ResolvedTable, partitionSpec, isExtended) if isSessionCatalog(r.catalog) =>

resolved.table match {
case _: V1Table =>
DescribeTableCommand(getTableIdentifier(resolved), partitionSpec, isExtended)
case _ =>
// The v1 `DescribeTableCommand` can describe view as well.
if (isView(resolved.identifier.asMultipartIdentifier)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before we reach here, we may already fail with table/view mismatch.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I checked with hive: https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-DescribeTable/View/MaterializedView/Column

The DESCRIBE command works for both table and view, in Spark we have a weird parser rule DESC TABLE? which makes people think it's for table only.

We can keep the parser rule, but we should rename DescribeTable to DescribeRelation, and use UnresolvedRelation to allow both table and view.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've open #27187 to refine it.

This is a feature we missed when designing the new framework, so I opened a separated PR to update the framework to support accepting both table and view like DESCRIBE command.

DescribeTableCommand(getTableIdentifier(resolved), partitionSpec, isExtended)
} else {
if (partitionSpec.nonEmpty) {
throw new AnalysisException(
"DESCRIBE TABLE does not support partition for v2 tables.")
}
d
}
val r = UnresolvedV2Relation(nameParts, catalog.asTableCatalog, tbl.asIdentifier)
DescribeTable(r, isExtended)
}
}

case DescribeColumnStatement(
Expand Down Expand Up @@ -483,10 +482,8 @@ class ResolveSessionCatalog(
replace,
viewType)

case ShowTablePropertiesStatement(SessionCatalogAndTable(_, tbl), propertyKey) =>
ShowTablePropertiesCommand(
tbl.asTableIdentifier,
propertyKey)
case ShowTableProperties(SessionCatalogAndResolvedTable(resolved), propertyKey) =>
ShowTablePropertiesCommand(getTableIdentifier(resolved), propertyKey)

case DescribeFunctionStatement(CatalogAndIdentifier(catalog, ident), extended) =>
val functionIdent =
Expand Down Expand Up @@ -586,6 +583,16 @@ class ResolveSessionCatalog(
}
}

object SessionCatalogAndResolvedTable {
def unapply(resolved: ResolvedTable): Option[ResolvedTable] = {
if (isSessionCatalog(resolved.catalog)) {
Some(resolved)
} else {
None
}
}
}

object SessionCatalogAndNamespace {
def unapply(resolved: ResolvedNamespace): Option[(SupportsNamespaces, Seq[String])] =
if (isSessionCatalog(resolved.catalog)) {
Expand All @@ -595,6 +602,11 @@ class ResolveSessionCatalog(
}
}

private def getTableIdentifier(resolved: ResolvedTable): TableIdentifier = {
Comment thread
imback82 marked this conversation as resolved.
Outdated
assert(resolved.identifier.namespace.length < 2)
TableIdentifier(resolved.identifier.name, resolved.identifier.namespace.headOption)
}

private def assertTopLevelColumn(colName: Seq[String], command: String): Unit = {
if (colName.length > 1) {
throw new AnalysisException(s"$command does not support nested column: ${colName.quoted}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,10 @@ object DataSourceV2Strategy extends Strategy with PredicateHelper {
case desc @ DescribeNamespace(ResolvedNamespace(catalog, ns), extended) =>
DescribeNamespaceExec(desc.output, catalog, ns, extended) :: Nil

case desc @ DescribeTable(DataSourceV2Relation(table, _, _), isExtended) =>
case desc @ DescribeTable(ResolvedTable(_, _, table), partitionSpec, isExtended) =>
if (partitionSpec.nonEmpty) {
throw new AnalysisException("DESCRIBE TABLE does not support partition for v2 tables.")
}
DescribeTableExec(desc.output, table, isExtended) :: Nil

case DropTable(catalog, ident, ifExists) =>
Expand Down Expand Up @@ -246,7 +249,7 @@ object DataSourceV2Strategy extends Strategy with PredicateHelper {
case r: ShowCurrentNamespace =>
ShowCurrentNamespaceExec(r.output, r.catalogManager) :: Nil

case r @ ShowTableProperties(DataSourceV2Relation(table, _, _), propertyKey) =>
case r @ ShowTableProperties(ResolvedTable(_, _, table), propertyKey) =>
ShowTablePropertiesExec(r.output, table, propertyKey) :: Nil

case _ => Nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,6 @@ class SQLQueryTestSuite extends QueryTest with SharedSparkSession {
case _: Join | _: Aggregate | _: Generate | _: Sample | _: Distinct => false
case _: DescribeCommandBase
| _: DescribeColumnCommand
| _: DescribeTableStatement
| _: DescribeColumnStatement => true
case PhysicalOperation(_, _, Sort(_, true, _)) => true
case _ => plan.children.iterator.exists(isSorted)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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.connector

import org.scalatest.BeforeAndAfter

import org.apache.spark.sql.{AnalysisException, QueryTest}
import org.apache.spark.sql.test.SharedSparkSession

class TableResolutionSuite extends QueryTest with SharedSparkSession with BeforeAndAfter{
Comment thread
imback82 marked this conversation as resolved.
Outdated

before {
spark.conf.set("spark.sql.catalog.testcat", classOf[InMemoryTableCatalog].getName)
}

after {
spark.sessionState.catalog.reset()
spark.sessionState.catalogManager.reset()
spark.sessionState.conf.clear()
}

test("V2 commands should look up temp view first") {
val tbl = "t"
val commands = Seq(
s"DESCRIBE $tbl",
s"SHOW TBLPROPERTIES $tbl"
// s"ALTER TABLE $tbl ADD COLUMN data string"
)

withTempView(s"$tbl") {
withTable(s"testcat.ns.$tbl") {
sql(s"CREATE TEMPORARY VIEW $tbl AS SELECT 1 AS i")
sql(s"CREATE TABLE testcat.ns.$tbl USING csv AS SELECT 2 AS i")
sql("USE testcat.ns")

commands.foreach { command =>
val ex = intercept[AnalysisException] {
sql(command)
}
assert(ex.getMessage.contains(s"$tbl is a temp view not table."))
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.apache.spark.sql.catalyst.{FunctionIdentifier, TableIdentifier}
import org.apache.spark.sql.catalyst.analysis.{AnalysisTest, UnresolvedAlias, UnresolvedAttribute, UnresolvedRelation, UnresolvedStar}
import org.apache.spark.sql.catalyst.catalog.{BucketSpec, CatalogStorageFormat, CatalogTable, CatalogTableType}
import org.apache.spark.sql.catalyst.expressions.{Ascending, Concat, SortOrder}
import org.apache.spark.sql.catalyst.plans.logical.{DescribeColumnStatement, DescribeTableStatement, LogicalPlan, Project, RepartitionByExpression, Sort}
import org.apache.spark.sql.catalyst.plans.logical.{LogicalPlan, Project, RepartitionByExpression, Sort}
import org.apache.spark.sql.execution.command._
import org.apache.spark.sql.execution.datasources.{CreateTable, RefreshResource}
import org.apache.spark.sql.internal.{HiveSerDe, SQLConf}
Expand Down
Loading