Skip to content

Commit 0c19497

Browse files
imback82cloud-fan
authored andcommitted
[SPARK-33815][SQL] Migrate ALTER TABLE ... SET [SERDE|SERDEPROPERTIES] to use UnresolvedTable to resolve the identifier
### What changes were proposed in this pull request? This PR proposes to migrate `ALTER TABLE ... SET [SERDE|SERDEPROPERTIES` to use `UnresolvedTable` 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 `ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]` is not supported for v2 tables. ### Why are the changes needed? The PR makes the resolution consistent behavior consistent. For example, ```scala sql("CREATE DATABASE test") sql("CREATE TABLE spark_catalog.test.t (id bigint, val string) USING csv PARTITIONED BY (id)") sql("CREATE TEMPORARY VIEW t AS SELECT 2") sql("USE spark_catalog.test") sql("ALTER TABLE t SET SERDE 'serdename'") // works fine ``` , but after this PR: ``` sql("ALTER TABLE t SET SERDE 'serdename'") org.apache.spark.sql.AnalysisException: t is a temp view. 'ALTER TABLE ... SET [SERDE|SERDEPROPERTIES\' expects a table; line 1 pos 0 ``` , which is the consistent behavior with other commands. ### Does this PR introduce _any_ user-facing change? After this PR, `t` in the above example is resolved to a temp view first instead of `spark_catalog.test.t`. ### How was this patch tested? Updated existing tests. Closes #30813 from imback82/alter_table_serde_v2. Authored-by: Terry Kim <[email protected]> Signed-off-by: Wenchen Fan <[email protected]>
1 parent 0c12900 commit 0c19497

File tree

9 files changed

+66
-37
lines changed

9 files changed

+66
-37
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3806,7 +3806,7 @@ class AstBuilder extends SqlBaseBaseVisitor[AnyRef] with SQLConfHelper with Logg
38063806
}
38073807

38083808
/**
3809-
* Create an [[AlterTableSerDePropertiesStatement]]
3809+
* Create an [[AlterTableSerDeProperties]]
38103810
*
38113811
* For example:
38123812
* {{{
@@ -3816,8 +3816,10 @@ class AstBuilder extends SqlBaseBaseVisitor[AnyRef] with SQLConfHelper with Logg
38163816
* }}}
38173817
*/
38183818
override def visitSetTableSerDe(ctx: SetTableSerDeContext): LogicalPlan = withOrigin(ctx) {
3819-
AlterTableSerDePropertiesStatement(
3820-
visitMultipartIdentifier(ctx.multipartIdentifier),
3819+
AlterTableSerDeProperties(
3820+
UnresolvedTable(
3821+
visitMultipartIdentifier(ctx.multipartIdentifier),
3822+
"ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]"),
38213823
Option(ctx.STRING).map(string),
38223824
Option(ctx.tablePropertyList).map(visitPropertyKeyValues),
38233825
// TODO a partition spec is allowed to have optional values. This is currently violated.

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -300,15 +300,6 @@ case class AlterTableRenamePartitionStatement(
300300
from: TablePartitionSpec,
301301
to: TablePartitionSpec) extends ParsedStatement
302302

303-
/**
304-
* ALTER TABLE ... SERDEPROPERTIES command, as parsed from SQL
305-
*/
306-
case class AlterTableSerDePropertiesStatement(
307-
tableName: Seq[String],
308-
serdeClassName: Option[String],
309-
serdeProperties: Option[Map[String, String]],
310-
partitionSpec: Option[TablePartitionSpec]) extends ParsedStatement
311-
312303
/**
313304
* An INSERT INTO statement, as parsed from SQL.
314305
*

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,17 @@ case class AlterViewUnsetProperties(
777777
override def children: Seq[LogicalPlan] = child :: Nil
778778
}
779779

780+
/**
781+
* The logical plan of the ALTER TABLE ... SET [SERDE|SERDEPROPERTIES] command.
782+
*/
783+
case class AlterTableSerDeProperties(
784+
child: LogicalPlan,
785+
serdeClassName: Option[String],
786+
serdeProperties: Option[Map[String, String]],
787+
partitionSpec: Option[TablePartitionSpec]) extends Command {
788+
override def children: Seq[LogicalPlan] = child :: Nil
789+
}
790+
780791
/**
781792
* The logical plan of the CACHE TABLE command.
782793
*/

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

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2134,8 +2134,11 @@ class DDLParserSuite extends AnalysisTest {
21342134
test("alter table: SerDe properties") {
21352135
val sql1 = "ALTER TABLE table_name SET SERDE 'org.apache.class'"
21362136
val parsed1 = parsePlan(sql1)
2137-
val expected1 = AlterTableSerDePropertiesStatement(
2138-
Seq("table_name"), Some("org.apache.class"), None, None)
2137+
val expected1 = AlterTableSerDeProperties(
2138+
UnresolvedTable(Seq("table_name"), "ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]"),
2139+
Some("org.apache.class"),
2140+
None,
2141+
None)
21392142
comparePlans(parsed1, expected1)
21402143

21412144
val sql2 =
@@ -2144,8 +2147,8 @@ class DDLParserSuite extends AnalysisTest {
21442147
|WITH SERDEPROPERTIES ('columns'='foo,bar', 'field.delim' = ',')
21452148
""".stripMargin
21462149
val parsed2 = parsePlan(sql2)
2147-
val expected2 = AlterTableSerDePropertiesStatement(
2148-
Seq("table_name"),
2150+
val expected2 = AlterTableSerDeProperties(
2151+
UnresolvedTable(Seq("table_name"), "ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]"),
21492152
Some("org.apache.class"),
21502153
Some(Map("columns" -> "foo,bar", "field.delim" -> ",")),
21512154
None)
@@ -2157,8 +2160,11 @@ class DDLParserSuite extends AnalysisTest {
21572160
|SET SERDEPROPERTIES ('columns'='foo,bar', 'field.delim' = ',')
21582161
""".stripMargin
21592162
val parsed3 = parsePlan(sql3)
2160-
val expected3 = AlterTableSerDePropertiesStatement(
2161-
Seq("table_name"), None, Some(Map("columns" -> "foo,bar", "field.delim" -> ",")), None)
2163+
val expected3 = AlterTableSerDeProperties(
2164+
UnresolvedTable(Seq("table_name"), "ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]"),
2165+
None,
2166+
Some(Map("columns" -> "foo,bar", "field.delim" -> ",")),
2167+
None)
21622168
comparePlans(parsed3, expected3)
21632169

21642170
val sql4 =
@@ -2168,8 +2174,8 @@ class DDLParserSuite extends AnalysisTest {
21682174
|WITH SERDEPROPERTIES ('columns'='foo,bar', 'field.delim' = ',')
21692175
""".stripMargin
21702176
val parsed4 = parsePlan(sql4)
2171-
val expected4 = AlterTableSerDePropertiesStatement(
2172-
Seq("table_name"),
2177+
val expected4 = AlterTableSerDeProperties(
2178+
UnresolvedTable(Seq("table_name"), "ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]"),
21732179
Some("org.apache.class"),
21742180
Some(Map("columns" -> "foo,bar", "field.delim" -> ",")),
21752181
Some(Map("test" -> "1", "dt" -> "2008-08-08", "country" -> "us")))
@@ -2181,8 +2187,8 @@ class DDLParserSuite extends AnalysisTest {
21812187
|SET SERDEPROPERTIES ('columns'='foo,bar', 'field.delim' = ',')
21822188
""".stripMargin
21832189
val parsed5 = parsePlan(sql5)
2184-
val expected5 = AlterTableSerDePropertiesStatement(
2185-
Seq("table_name"),
2190+
val expected5 = AlterTableSerDeProperties(
2191+
UnresolvedTable(Seq("table_name"), "ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]"),
21862192
None,
21872193
Some(Map("columns" -> "foo,bar", "field.delim" -> ",")),
21882194
Some(Map("test" -> "1", "dt" -> "2008-08-08", "country" -> "us")))
@@ -2194,8 +2200,8 @@ class DDLParserSuite extends AnalysisTest {
21942200
|WITH SERDEPROPERTIES ('columns'='foo,bar', 'field.delim' = ',')
21952201
""".stripMargin
21962202
val parsed6 = parsePlan(sql6)
2197-
val expected6 = AlterTableSerDePropertiesStatement(
2198-
Seq("a", "b", "c"),
2203+
val expected6 = AlterTableSerDeProperties(
2204+
UnresolvedTable(Seq("a", "b", "c"), "ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]"),
21992205
Some("org.apache.class"),
22002206
Some(Map("columns" -> "foo,bar", "field.delim" -> ",")),
22012207
None)
@@ -2207,8 +2213,8 @@ class DDLParserSuite extends AnalysisTest {
22072213
|SET SERDEPROPERTIES ('columns'='foo,bar', 'field.delim' = ',')
22082214
""".stripMargin
22092215
val parsed7 = parsePlan(sql7)
2210-
val expected7 = AlterTableSerDePropertiesStatement(
2211-
Seq("a", "b", "c"),
2216+
val expected7 = AlterTableSerDeProperties(
2217+
UnresolvedTable(Seq("a", "b", "c"), "ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]"),
22122218
None,
22132219
Some(Map("columns" -> "foo,bar", "field.delim" -> ",")),
22142220
Some(Map("test" -> "1", "dt" -> "2008-08-08", "country" -> "us")))

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -476,10 +476,13 @@ class ResolveSessionCatalog(
476476
purge,
477477
retainData = false)
478478

479-
case AlterTableSerDePropertiesStatement(tbl, serdeClassName, serdeProperties, partitionSpec) =>
480-
val v1TableName = parseV1Table(tbl, "ALTER TABLE SerDe Properties")
479+
case AlterTableSerDeProperties(
480+
ResolvedV1TableIdentifier(ident),
481+
serdeClassName,
482+
serdeProperties,
483+
partitionSpec) =>
481484
AlterTableSerDePropertiesCommand(
482-
v1TableName.asTableIdentifier,
485+
ident.asTableIdentifier,
483486
serdeClassName,
484487
serdeProperties,
485488
partitionSpec)

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,10 @@ class DataSourceV2Strategy(session: SparkSession) extends Strategy with Predicat
334334
throw new AnalysisException(
335335
"ALTER TABLE ... RECOVER PARTITIONS is not supported for v2 tables.")
336336

337+
case AlterTableSerDeProperties(_: ResolvedTable, _, _, _) =>
338+
throw new AnalysisException(
339+
"ALTER TABLE ... SET [SERDE|SERDEPROPERTIES] is not supported for v2 tables.")
340+
337341
case LoadData(_: ResolvedTable, _, _, _, _) =>
338342
throw new AnalysisException("LOAD DATA is not supported for v2 tables.")
339343

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
@@ -2120,7 +2120,8 @@ class DataSourceV2SQLSuite
21202120
val e = intercept[AnalysisException] {
21212121
sql(s"ALTER TABLE $t SET SERDEPROPERTIES ('columns'='foo,bar', 'field.delim' = ',')")
21222122
}
2123-
assert(e.message.contains("ALTER TABLE SerDe Properties is only supported with v1 tables"))
2123+
assert(e.message.contains(
2124+
"ALTER TABLE ... SET [SERDE|SERDEPROPERTIES] is not supported for v2 tables"))
21242125
}
21252126
}
21262127

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,15 @@ abstract class SQLViewSuite extends QueryTest with SQLTestUtils {
140140
val viewName = "testView"
141141
withTempView(viewName) {
142142
spark.range(10).createTempView(viewName)
143-
assertNoSuchTable(s"ALTER TABLE $viewName SET SERDE 'whatever'")
144-
assertNoSuchTable(s"ALTER TABLE $viewName PARTITION (a=1, b=2) SET SERDE 'whatever'")
145-
assertNoSuchTable(s"ALTER TABLE $viewName SET SERDEPROPERTIES ('p' = 'an')")
143+
assertAnalysisError(
144+
s"ALTER TABLE $viewName SET SERDE 'whatever'",
145+
s"$viewName is a temp view. 'ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]' expects a table")
146+
assertAnalysisError(
147+
s"ALTER TABLE $viewName PARTITION (a=1, b=2) SET SERDE 'whatever'",
148+
s"$viewName is a temp view. 'ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]' expects a table")
149+
assertAnalysisError(
150+
s"ALTER TABLE $viewName SET SERDEPROPERTIES ('p' = 'an')",
151+
s"$viewName is a temp view. 'ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]' expects a table")
146152
assertNoSuchTable(s"ALTER TABLE $viewName PARTITION (a='4') RENAME TO PARTITION (a='5')")
147153
assertAnalysisError(
148154
s"ALTER TABLE $viewName RECOVER PARTITIONS",

sql/hive/src/test/scala/org/apache/spark/sql/hive/execution/HiveDDLSuite.scala

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -888,12 +888,17 @@ class HiveDDLSuite
888888

889889
assertErrorForAlterTableOnView(s"ALTER TABLE $oldViewName SET LOCATION '/path/to/home'")
890890

891-
assertErrorForAlterTableOnView(s"ALTER TABLE $oldViewName SET SERDE 'whatever'")
891+
assertAnalysisError(
892+
s"ALTER TABLE $oldViewName SET SERDE 'whatever'",
893+
s"$oldViewName is a view. 'ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]' expects a table.")
892894

893-
assertErrorForAlterTableOnView(s"ALTER TABLE $oldViewName SET SERDEPROPERTIES ('x' = 'y')")
895+
assertAnalysisError(
896+
s"ALTER TABLE $oldViewName SET SERDEPROPERTIES ('x' = 'y')",
897+
s"$oldViewName is a view. 'ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]' expects a table.")
894898

895-
assertErrorForAlterTableOnView(
896-
s"ALTER TABLE $oldViewName PARTITION (a=1, b=2) SET SERDEPROPERTIES ('x' = 'y')")
899+
assertAnalysisError(
900+
s"ALTER TABLE $oldViewName PARTITION (a=1, b=2) SET SERDEPROPERTIES ('x' = 'y')",
901+
s"$oldViewName is a view. 'ALTER TABLE ... SET [SERDE|SERDEPROPERTIES]' expects a table.")
897902

898903
assertAnalysisError(
899904
s"ALTER TABLE $oldViewName RECOVER PARTITIONS",

0 commit comments

Comments
 (0)