Skip to content

Commit 0593ac6

Browse files
cloud-fandongjoon-hyun
authored andcommitted
[SPARK-50541][SQL][FOLLOWUP] Migrate DESC TABLE AS JSON to v2 command
### What changes were proposed in this pull request? This is a follow-up of #49139 to use v2 command to simplify the code. Now we only need one logical plan and all the implementation is centralized to that logical plan, no need to touch other analyzer/planner rules. ### Why are the changes needed? code simplification ### Does this PR introduce _any_ user-facing change? no, this feature is not released yet. ### How was this patch tested? update tests ### Was this patch authored or co-authored using generative AI tooling? no Closes #49466 from cloud-fan/as-json. Authored-by: Wenchen Fan <[email protected]> Signed-off-by: Dongjoon Hyun <[email protected]>
1 parent d792865 commit 0593ac6

File tree

14 files changed

+544
-632
lines changed

14 files changed

+544
-632
lines changed

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala

+1-42
Original file line numberDiff line numberDiff line change
@@ -3494,7 +3494,7 @@ class AstBuilder extends DataTypeAstBuilder
34943494
/**
34953495
* Create an [[UnresolvedTableOrView]] from a multi-part identifier.
34963496
*/
3497-
private def createUnresolvedTableOrView(
3497+
protected def createUnresolvedTableOrView(
34983498
ctx: IdentifierReferenceContext,
34993499
commandName: String,
35003500
allowTempView: Boolean = true): LogicalPlan = withOrigin(ctx) {
@@ -5198,47 +5198,6 @@ class AstBuilder extends DataTypeAstBuilder
51985198
visitLocationSpec(ctx.locationSpec))
51995199
}
52005200

5201-
/**
5202-
* Create a [[DescribeColumn]] or [[DescribeRelation]] commands.
5203-
*/
5204-
override def visitDescribeRelation(ctx: DescribeRelationContext): LogicalPlan = withOrigin(ctx) {
5205-
val isExtended = ctx.EXTENDED != null || ctx.FORMATTED != null
5206-
val asJson = ctx.JSON != null
5207-
if (asJson && !isExtended) {
5208-
val tableName = ctx.identifierReference.getText.split("\\.").lastOption.getOrElse("table")
5209-
throw QueryCompilationErrors.describeJsonNotExtendedError(tableName)
5210-
}
5211-
val relation = createUnresolvedTableOrView(ctx.identifierReference, "DESCRIBE TABLE")
5212-
if (ctx.describeColName != null) {
5213-
if (ctx.partitionSpec != null) {
5214-
throw QueryParsingErrors.descColumnForPartitionUnsupportedError(ctx)
5215-
} else if (asJson) {
5216-
throw QueryCompilationErrors.describeColJsonUnsupportedError()
5217-
} else {
5218-
DescribeColumn(
5219-
relation,
5220-
UnresolvedAttribute(ctx.describeColName.nameParts.asScala.map(_.getText).toSeq),
5221-
isExtended)
5222-
}
5223-
} else {
5224-
val partitionSpec = if (ctx.partitionSpec != null) {
5225-
// According to the syntax, visitPartitionSpec returns `Map[String, Option[String]]`.
5226-
visitPartitionSpec(ctx.partitionSpec).map {
5227-
case (key, Some(value)) => key -> value
5228-
case (key, _) =>
5229-
throw QueryParsingErrors.emptyPartitionKeyError(key, ctx.partitionSpec)
5230-
}
5231-
} else {
5232-
Map.empty[String, String]
5233-
}
5234-
if (asJson) {
5235-
DescribeRelationJson(relation, partitionSpec, isExtended)
5236-
} else {
5237-
DescribeRelation(relation, partitionSpec, isExtended)
5238-
}
5239-
}
5240-
}
5241-
52425201
/**
52435202
* Create an [[AnalyzeTable]], or an [[AnalyzeColumn]].
52445203
* Example SQL for analyzing a table or a set of partitions :

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/plans/logical/v2Commands.scala

-13
Original file line numberDiff line numberDiff line change
@@ -691,19 +691,6 @@ object DescribeRelation {
691691
def getOutputAttrs: Seq[Attribute] = DescribeCommandSchema.describeTableAttributes()
692692
}
693693

694-
/**
695-
* The logical plan of the DESCRIBE relation_name AS JSON command.
696-
*/
697-
case class DescribeRelationJson(
698-
relation: LogicalPlan,
699-
partitionSpec: TablePartitionSpec,
700-
isExtended: Boolean) extends UnaryCommand {
701-
override val output: Seq[Attribute] = DescribeCommandSchema.describeJsonTableAttributes()
702-
override def child: LogicalPlan = relation
703-
override protected def withNewChildInternal(newChild: LogicalPlan): DescribeRelationJson =
704-
copy(relation = newChild)
705-
}
706-
707694
/**
708695
* The logical plan of the DESCRIBE relation_name col_name command.
709696
*/

sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnalysisExceptionPositionSuite.scala

-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ class AnalysisExceptionPositionSuite extends AnalysisTest {
4040
}
4141

4242
test("SPARK-34057: UnresolvedTableOrView should retain sql text position") {
43-
verifyTableOrViewPosition("DESCRIBE TABLE unknown", "unknown")
4443
verifyTableOrPermanentViewPosition("ANALYZE TABLE unknown COMPUTE STATISTICS", "unknown")
4544
verifyTableOrViewPosition("ANALYZE TABLE unknown COMPUTE STATISTICS FOR COLUMNS col", "unknown")
4645
verifyTableOrViewPosition("ANALYZE TABLE unknown COMPUTE STATISTICS FOR ALL COLUMNS", "unknown")

sql/core/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveSessionCatalog.scala

-4
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,6 @@ class ResolveSessionCatalog(val catalogManager: CatalogManager)
152152
case RenameTable(ResolvedV1TableOrViewIdentifier(oldIdent), newName, isView) =>
153153
AlterTableRenameCommand(oldIdent, newName.asTableIdentifier, isView)
154154

155-
case DescribeRelationJson(
156-
ResolvedV1TableOrViewIdentifier(ident), partitionSpec, isExtended) =>
157-
DescribeTableJsonCommand(ident, partitionSpec, isExtended)
158-
159155
// Use v1 command to describe (temp) view, as v2 catalog doesn't support view yet.
160156
case DescribeRelation(
161157
ResolvedV1TableOrViewIdentifier(ident), partitionSpec, isExtended, output) =>

sql/core/src/main/scala/org/apache/spark/sql/execution/SparkSqlParser.scala

+43-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import org.antlr.v4.runtime.tree.TerminalNode
2727

2828
import org.apache.spark.SparkException
2929
import org.apache.spark.sql.catalyst.{FunctionIdentifier, TableIdentifier}
30-
import org.apache.spark.sql.catalyst.analysis.{GlobalTempView, LocalTempView, PersistedView, PlanWithUnresolvedIdentifier, SchemaEvolution, SchemaTypeEvolution, UnresolvedFunctionName, UnresolvedIdentifier, UnresolvedNamespace}
30+
import org.apache.spark.sql.catalyst.analysis.{GlobalTempView, LocalTempView, PersistedView, PlanWithUnresolvedIdentifier, SchemaEvolution, SchemaTypeEvolution, UnresolvedAttribute, UnresolvedFunctionName, UnresolvedIdentifier, UnresolvedNamespace}
3131
import org.apache.spark.sql.catalyst.catalog._
3232
import org.apache.spark.sql.catalyst.expressions.{Expression, Literal}
3333
import org.apache.spark.sql.catalyst.parser._
@@ -1153,4 +1153,46 @@ class SparkSqlAstBuilder extends AstBuilder {
11531153
withIdentClause(ctx.identifierReference(), UnresolvedNamespace(_)),
11541154
cleanedProperties)
11551155
}
1156+
1157+
/**
1158+
* Create a [[DescribeColumn]] or [[DescribeRelation]] or [[DescribeRelationAsJsonCommand]]
1159+
* command.
1160+
*/
1161+
override def visitDescribeRelation(ctx: DescribeRelationContext): LogicalPlan = withOrigin(ctx) {
1162+
val isExtended = ctx.EXTENDED != null || ctx.FORMATTED != null
1163+
val asJson = ctx.JSON != null
1164+
if (asJson && !isExtended) {
1165+
val tableName = ctx.identifierReference.getText.split("\\.").lastOption.getOrElse("table")
1166+
throw QueryCompilationErrors.describeJsonNotExtendedError(tableName)
1167+
}
1168+
val relation = createUnresolvedTableOrView(ctx.identifierReference, "DESCRIBE TABLE")
1169+
if (ctx.describeColName != null) {
1170+
if (ctx.partitionSpec != null) {
1171+
throw QueryParsingErrors.descColumnForPartitionUnsupportedError(ctx)
1172+
} else if (asJson) {
1173+
throw QueryCompilationErrors.describeColJsonUnsupportedError()
1174+
} else {
1175+
DescribeColumn(
1176+
relation,
1177+
UnresolvedAttribute(ctx.describeColName.nameParts.asScala.map(_.getText).toSeq),
1178+
isExtended)
1179+
}
1180+
} else {
1181+
val partitionSpec = if (ctx.partitionSpec != null) {
1182+
// According to the syntax, visitPartitionSpec returns `Map[String, Option[String]]`.
1183+
visitPartitionSpec(ctx.partitionSpec).map {
1184+
case (key, Some(value)) => key -> value
1185+
case (key, _) =>
1186+
throw QueryParsingErrors.emptyPartitionKeyError(key, ctx.partitionSpec)
1187+
}
1188+
} else {
1189+
Map.empty[String, String]
1190+
}
1191+
if (asJson) {
1192+
DescribeRelationJsonCommand(relation, partitionSpec, isExtended)
1193+
} else {
1194+
DescribeRelation(relation, partitionSpec, isExtended)
1195+
}
1196+
}
1197+
}
11561198
}

0 commit comments

Comments
 (0)