Skip to content

Commit 6d5d030

Browse files
imback82cloud-fan
authored andcommitted
[SPARK-33414][SQL] Migrate SHOW CREATE TABLE command to use UnresolvedTableOrView to resolve the identifier
### What changes were proposed in this pull request? This PR proposes to migrate `SHOW CREATE TABLE` to use `UnresolvedTableOrView` to resolve the table identifier. This allows consistent resolution rules (temp view first, etc.) to be applied for both v1/v2 commands. More info about the consistent resolution rule proposal can be found in [JIRA](https://issues.apache.org/jira/browse/SPARK-29900) or [proposal doc](https://docs.google.com/document/d/1hvLjGA8y_W_hhilpngXVub1Ebv8RsMap986nENCFnrg/edit?usp=sharing). Note that `SHOW CREATE TABLE` works only with a v1 table and a permanent view, and not supported for v2 tables. ### Why are the changes needed? The changes allow consistent resolution behavior when resolving the table identifier. For example, the following is the current behavior: ```scala sql("CREATE TEMPORARY VIEW t AS SELECT 1") sql("CREATE DATABASE db") sql("CREATE TABLE t (key INT, value STRING) USING hive") sql("USE db") sql("SHOW CREATE TABLE t AS SERDE") // Succeeds ``` With this change, `SHOW CREATE TABLE ... AS SERDE` above fails with the following: ``` org.apache.spark.sql.AnalysisException: t is a temp view not table or permanent view.; line 1 pos 0 at org.apache.spark.sql.catalyst.analysis.package$AnalysisErrorAt.failAnalysis(package.scala:42) at org.apache.spark.sql.catalyst.analysis.Analyzer$ResolveTempViews$$anonfun$apply$7.$anonfun$applyOrElse$43(Analyzer.scala:883) at scala.Option.map(Option.scala:230) ``` , which is expected since temporary view is resolved first and `SHOW CREATE TABLE ... AS SERDE` doesn't support a temporary view. Note that there is no behavior change for `SHOW CREATE TABLE` without `AS SERDE` since it was already resolving to a temporary view first. See below for more detail. ### Does this PR introduce _any_ user-facing change? After this PR, `SHOW CREATE TABLE t AS SERDE` is resolved to a temp view `t` instead of table `db.t` in the above scenario. Note that there is no behavior change for `SHOW CREATE TABLE` without `AS SERDE`, but the exception message changes from `SHOW CREATE TABLE is not supported on a temporary view` to `t is a temp view not table or permanent view`. ### How was this patch tested? Updated existing tests. Closes #30321 from imback82/show_create_table. Authored-by: Terry Kim <yuminkim@gmail.com> Signed-off-by: Wenchen Fan <wenchen@databricks.com>
1 parent 1e2eeda commit 6d5d030

File tree

9 files changed

+36
-22
lines changed

9 files changed

+36
-22
lines changed

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3301,10 +3301,14 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging
33013301
}
33023302

33033303
/**
3304-
* Creates a [[ShowCreateTableStatement]]
3304+
* Creates a [[ShowCreateTable]]
33053305
*/
33063306
override def visitShowCreateTable(ctx: ShowCreateTableContext): LogicalPlan = withOrigin(ctx) {
3307-
ShowCreateTableStatement(visitMultipartIdentifier(ctx.multipartIdentifier()), ctx.SERDE != null)
3307+
ShowCreateTable(
3308+
UnresolvedTableOrView(
3309+
visitMultipartIdentifier(ctx.multipartIdentifier()),
3310+
allowTempView = false),
3311+
ctx.SERDE != null)
33083312
}
33093313

33103314
/**

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

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,6 @@ case class UseStatement(isNamespaceSet: Boolean, nameParts: Seq[String]) extends
347347
*/
348348
case class RepairTableStatement(tableName: Seq[String]) extends ParsedStatement
349349

350-
/**
351-
* A SHOW CREATE TABLE statement, as parsed from SQL.
352-
*/
353-
case class ShowCreateTableStatement(
354-
tableName: Seq[String],
355-
asSerde: Boolean = false) extends ParsedStatement
356-
357350
/**
358351
* A CACHE TABLE statement, as parsed from SQL
359352
*/

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,3 +622,10 @@ case class LoadData(
622622
partition: Option[TablePartitionSpec]) extends Command {
623623
override def children: Seq[LogicalPlan] = child :: Nil
624624
}
625+
626+
/**
627+
* The logical plan of the SHOW CREATE TABLE command.
628+
*/
629+
case class ShowCreateTable(child: LogicalPlan, asSerde: Boolean = false) extends Command {
630+
override def children: Seq[LogicalPlan] = child :: Nil
631+
}

sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/DDLParserSuite.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1583,7 +1583,13 @@ class DDLParserSuite extends AnalysisTest {
15831583
test("SHOW CREATE table") {
15841584
comparePlans(
15851585
parsePlan("SHOW CREATE TABLE a.b.c"),
1586-
ShowCreateTableStatement(Seq("a", "b", "c")))
1586+
ShowCreateTable(UnresolvedTableOrView(Seq("a", "b", "c"), allowTempView = false)))
1587+
1588+
comparePlans(
1589+
parsePlan("SHOW CREATE TABLE a.b.c AS SERDE"),
1590+
ShowCreateTable(
1591+
UnresolvedTableOrView(Seq("a", "b", "c"), allowTempView = false),
1592+
asSerde = true))
15871593
}
15881594

15891595
test("CACHE TABLE") {

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -434,13 +434,12 @@ class ResolveSessionCatalog(
434434
isOverwrite,
435435
partition)
436436

437-
case ShowCreateTableStatement(tbl, asSerde) if !asSerde =>
438-
val name = parseTempViewOrV1Table(tbl, "SHOW CREATE TABLE")
439-
ShowCreateTableCommand(name.asTableIdentifier)
440-
441-
case ShowCreateTableStatement(tbl, asSerde) if asSerde =>
442-
val v1TableName = parseV1Table(tbl, "SHOW CREATE TABLE AS SERDE")
443-
ShowCreateTableAsSerdeCommand(v1TableName.asTableIdentifier)
437+
case ShowCreateTable(ResolvedV1TableOrViewIdentifier(ident), asSerde) =>
438+
if (asSerde) {
439+
ShowCreateTableAsSerdeCommand(ident.asTableIdentifier)
440+
} else {
441+
ShowCreateTableCommand(ident.asTableIdentifier)
442+
}
444443

445444
case CacheTableStatement(tbl, plan, isLazy, options) =>
446445
val name = if (plan.isDefined) {

sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/v2/DataSourceV2Strategy.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,9 @@ class DataSourceV2Strategy(session: SparkSession) extends Strategy with Predicat
286286
case LoadData(_: ResolvedTable, _, _, _, _) =>
287287
throw new AnalysisException("LOAD DATA is not supported for v2 tables.")
288288

289+
case ShowCreateTable(_: ResolvedTable, _) =>
290+
throw new AnalysisException("SHOW CREATE TABLE is not supported for v2 tables.")
291+
289292
case _ => Nil
290293
}
291294
}

sql/core/src/test/scala/org/apache/spark/sql/ShowCreateTableSuite.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,16 +155,17 @@ abstract class ShowCreateTableSuite extends QueryTest with SQLTestUtils {
155155
val ex = intercept[AnalysisException] {
156156
sql(s"SHOW CREATE TABLE $viewName")
157157
}
158-
assert(ex.getMessage.contains("SHOW CREATE TABLE is not supported on a temporary view"))
158+
assert(ex.getMessage.contains(s"$viewName is a temp view not table or permanent view"))
159159
}
160160

161161
withGlobalTempView(viewName) {
162162
sql(s"CREATE GLOBAL TEMPORARY VIEW $viewName AS SELECT 1 AS a")
163+
val globalTempViewDb = spark.sessionState.catalog.globalTempViewManager.database
163164
val ex = intercept[AnalysisException] {
164-
val globalTempViewDb = spark.sessionState.catalog.globalTempViewManager.database
165165
sql(s"SHOW CREATE TABLE $globalTempViewDb.$viewName")
166166
}
167-
assert(ex.getMessage.contains("SHOW CREATE TABLE is not supported on a temporary view"))
167+
assert(ex.getMessage.contains(
168+
s"$globalTempViewDb.$viewName is a temp view not table or permanent view"))
168169
}
169170
}
170171

sql/core/src/test/scala/org/apache/spark/sql/connector/DataSourceV2SQLSuite.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1954,7 +1954,8 @@ class DataSourceV2SQLSuite
19541954
val t = "testcat.ns1.ns2.tbl"
19551955
withTable(t) {
19561956
spark.sql(s"CREATE TABLE $t (id bigint, data string) USING foo")
1957-
testV1CommandSupportingTempView("SHOW CREATE TABLE", t)
1957+
testNotSupportedV2Command("SHOW CREATE TABLE", t)
1958+
testNotSupportedV2Command("SHOW CREATE TABLE", s"$t AS SERDE")
19581959
}
19591960
}
19601961

sql/core/src/test/scala/org/apache/spark/sql/execution/SQLViewSuite.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ abstract class SQLViewSuite extends QueryTest with SQLTestUtils {
176176
val e3 = intercept[AnalysisException] {
177177
sql(s"SHOW CREATE TABLE $viewName")
178178
}.getMessage
179-
assert(e3.contains("SHOW CREATE TABLE is not supported on a temporary view"))
179+
assert(e3.contains(s"$viewName is a temp view not table or permanent view"))
180180
assertNoSuchTable(s"SHOW PARTITIONS $viewName")
181181
val e4 = intercept[AnalysisException] {
182182
sql(s"ANALYZE TABLE $viewName COMPUTE STATISTICS")

0 commit comments

Comments
 (0)