This is an automated email from the ASF dual-hosted git repository. wenchen pushed a commit to branch branch-3.0 in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/branch-3.0 by this push: new 0c54037 [SPARK-30614][SQL] The native ALTER COLUMN syntax should change one property at a time 0c54037 is described below commit 0c5403721cc085c6515a585c39b195f75ef6ac7d Author: Terry Kim <yumin...@gmail.com> AuthorDate: Sat Feb 8 02:47:44 2020 +0800 [SPARK-30614][SQL] The native ALTER COLUMN syntax should change one property at a time ### What changes were proposed in this pull request? The current ALTER COLUMN syntax allows to change multiple properties at a time: ``` ALTER TABLE table=multipartIdentifier (ALTER | CHANGE) COLUMN? column=multipartIdentifier (TYPE dataType)? (COMMENT comment=STRING)? colPosition? ``` The SQL standard (section 11.12) only allows changing one property at a time. This is also true on other recent SQL systems like [snowflake](https://docs.snowflake.net/manuals/sql-reference/sql/alter-table-column.html) and [redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_ALTER_TABLE.html). (credit to cloud-fan) This PR proposes to change ALTER COLUMN to follow SQL standard, thus allows altering only one column property at a time. Note that ALTER COLUMN syntax being changed here is newly added in Spark 3.0, so it doesn't affect Spark 2.4 behavior. ### Why are the changes needed? To follow SQL standard (and other recent SQL systems) behavior. ### Does this PR introduce any user-facing change? Yes, now the user can update the column properties only one at a time. For example, ``` ALTER TABLE table1 ALTER COLUMN a.b.c TYPE bigint COMMENT 'new comment' ``` should be broken into ``` ALTER TABLE table1 ALTER COLUMN a.b.c TYPE bigint ALTER TABLE table1 ALTER COLUMN a.b.c COMMENT 'new comment' ``` ### How was this patch tested? Updated existing tests. Closes #27444 from imback82/alter_column_one_at_a_time. Authored-by: Terry Kim <yumin...@gmail.com> Signed-off-by: Wenchen Fan <wenc...@databricks.com> --- .../apache/spark/sql/catalyst/parser/SqlBase.g4 | 14 ++-- .../spark/sql/catalyst/parser/AstBuilder.scala | 78 ++++++++++++---------- .../spark/sql/catalyst/parser/DDLParserSuite.scala | 23 ++++--- .../catalyst/analysis/ResolveSessionCatalog.scala | 24 ++++--- .../resources/sql-tests/inputs/change-column.sql | 21 +++--- .../sql-tests/results/change-column.sql.out | 46 ++++++++++--- .../spark/sql/connector/AlterTableTests.scala | 13 ---- .../spark/sql/execution/command/DDLSuite.scala | 5 +- .../execution/command/PlanResolutionSuite.scala | 47 +++++++++---- 9 files changed, 165 insertions(+), 106 deletions(-) diff --git a/sql/catalyst/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBase.g4 b/sql/catalyst/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBase.g4 index 08d5ff5..563ef69 100644 --- a/sql/catalyst/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBase.g4 +++ b/sql/catalyst/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBase.g4 @@ -158,12 +158,9 @@ statement SET TBLPROPERTIES tablePropertyList #setTableProperties | ALTER (TABLE | VIEW) multipartIdentifier UNSET TBLPROPERTIES (IF EXISTS)? tablePropertyList #unsetTableProperties - | ALTER TABLE table=multipartIdentifier + |ALTER TABLE table=multipartIdentifier (ALTER | CHANGE) COLUMN? column=multipartIdentifier - (TYPE dataType)? commentSpec? colPosition? #alterTableColumn - | ALTER TABLE table=multipartIdentifier - ALTER COLUMN? column=multipartIdentifier - setOrDrop=(SET | DROP) NOT NULL #alterColumnNullability + alterColumnAction? #alterTableAlterColumn | ALTER TABLE table=multipartIdentifier partitionSpec? CHANGE COLUMN? colName=multipartIdentifier colType colPosition? #hiveChangeColumn @@ -983,6 +980,13 @@ number | MINUS? BIGDECIMAL_LITERAL #bigDecimalLiteral ; +alterColumnAction + : TYPE dataType + | commentSpec + | colPosition + | setOrDrop=(SET | DROP) NOT NULL + ; + // When `SQL_standard_keyword_behavior=true`, there are 2 kinds of keywords in Spark SQL. // - Reserved keywords: // Keywords that are reserved and can't be used as identifiers for table, view, column, diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala index e9ad844..6fc65e1 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala @@ -2940,55 +2940,61 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging } /** - * Parse a [[AlterTableAlterColumnStatement]] command. + * Parse a [[AlterTableAlterColumnStatement]] command to alter a column's property. * * For example: * {{{ * ALTER TABLE table1 ALTER COLUMN a.b.c TYPE bigint - * ALTER TABLE table1 ALTER COLUMN a.b.c TYPE bigint COMMENT 'new comment' + * ALTER TABLE table1 ALTER COLUMN a.b.c SET NOT NULL + * ALTER TABLE table1 ALTER COLUMN a.b.c DROP NOT NULL * ALTER TABLE table1 ALTER COLUMN a.b.c COMMENT 'new comment' + * ALTER TABLE table1 ALTER COLUMN a.b.c FIRST + * ALTER TABLE table1 ALTER COLUMN a.b.c AFTER x * }}} */ - override def visitAlterTableColumn( - ctx: AlterTableColumnContext): LogicalPlan = withOrigin(ctx) { - val verb = if (ctx.CHANGE != null) "CHANGE" else "ALTER" - if (ctx.dataType == null && ctx.commentSpec() == null && ctx.colPosition == null) { + override def visitAlterTableAlterColumn( + ctx: AlterTableAlterColumnContext): LogicalPlan = withOrigin(ctx) { + val action = ctx.alterColumnAction + if (action == null) { + val verb = if (ctx.CHANGE != null) "CHANGE" else "ALTER" operationNotAllowed( - s"ALTER TABLE table $verb COLUMN requires a TYPE or a COMMENT or a FIRST/AFTER", ctx) + s"ALTER TABLE table $verb COLUMN requires a TYPE, a SET/DROP, a COMMENT, or a FIRST/AFTER", + ctx) + } + + val dataType = if (action.dataType != null) { + Some(typedVisit[DataType](action.dataType)) + } else { + None + } + val nullable = if (action.setOrDrop != null) { + action.setOrDrop.getType match { + case SqlBaseParser.SET => Some(false) + case SqlBaseParser.DROP => Some(true) + } + } else { + None + } + val comment = if (action.commentSpec != null) { + Some(visitCommentSpec(action.commentSpec())) + } else { + None + } + val position = if (action.colPosition != null) { + Some(typedVisit[ColumnPosition](action.colPosition)) + } else { + None } + assert(Seq(dataType, nullable, comment, position).count(_.nonEmpty) == 1) + AlterTableAlterColumnStatement( visitMultipartIdentifier(ctx.table), typedVisit[Seq[String]](ctx.column), - dataType = Option(ctx.dataType).map(typedVisit[DataType]), - nullable = None, - comment = Option(ctx.commentSpec()).map(visitCommentSpec), - position = Option(ctx.colPosition).map(typedVisit[ColumnPosition])) - } - - /** - * Parse a [[AlterTableAlterColumnStatement]] command to change column nullability. - * - * For example: - * {{{ - * ALTER TABLE table1 ALTER COLUMN a.b.c SET NOT NULL - * ALTER TABLE table1 ALTER COLUMN a.b.c DROP NOT NULL - * }}} - */ - override def visitAlterColumnNullability(ctx: AlterColumnNullabilityContext): LogicalPlan = { - withOrigin(ctx) { - val nullable = ctx.setOrDrop.getType match { - case SqlBaseParser.SET => false - case SqlBaseParser.DROP => true - } - AlterTableAlterColumnStatement( - visitMultipartIdentifier(ctx.table), - typedVisit[Seq[String]](ctx.column), - dataType = None, - nullable = Some(nullable), - comment = None, - position = None) - } + dataType = dataType, + nullable = nullable, + comment = comment, + position = position) } /** diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/DDLParserSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/DDLParserSuite.scala index 56d5257..bc7b51f 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/DDLParserSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/DDLParserSuite.scala @@ -646,17 +646,18 @@ class DDLParserSuite extends AnalysisTest { Some(first()))) } - test("alter table: update column type, comment and position") { - comparePlans( - parsePlan("ALTER TABLE table_name CHANGE COLUMN a.b.c " + - "TYPE bigint COMMENT 'new comment' AFTER d"), - AlterTableAlterColumnStatement( - Seq("table_name"), - Seq("a", "b", "c"), - Some(LongType), - None, - Some("new comment"), - Some(after("d")))) + test("alter table: mutiple property changes are not allowed") { + intercept[ParseException] { + parsePlan("ALTER TABLE table_name ALTER COLUMN a.b.c " + + "TYPE bigint COMMENT 'new comment'")} + + intercept[ParseException] { + parsePlan("ALTER TABLE table_name ALTER COLUMN a.b.c " + + "TYPE bigint COMMENT AFTER d")} + + intercept[ParseException] { + parsePlan("ALTER TABLE table_name ALTER COLUMN a.b.c " + + "TYPE bigint COMMENT 'new comment' AFTER d")} } test("alter table: SET/DROP NOT NULL") { diff --git a/sql/core/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveSessionCatalog.scala b/sql/core/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveSessionCatalog.scala index 486e7f1..77d549c 100644 --- a/sql/core/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveSessionCatalog.scala +++ b/sql/core/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveSessionCatalog.scala @@ -77,10 +77,6 @@ class ResolveSessionCatalog( throw new AnalysisException( "ALTER COLUMN with qualified column is only supported with v2 tables.") } - if (a.dataType.isEmpty) { - throw new AnalysisException( - "ALTER COLUMN with v1 tables must specify new data type.") - } if (a.nullable.isDefined) { throw new AnalysisException( "ALTER COLUMN with v1 tables cannot specify NOT NULL.") @@ -92,17 +88,27 @@ class ResolveSessionCatalog( val builder = new MetadataBuilder // Add comment to metadata a.comment.map(c => builder.putString("comment", c)) + val colName = a.column(0) + val dataType = a.dataType.getOrElse { + v1Table.schema.findNestedField(Seq(colName), resolver = conf.resolver) + .map(_._2.dataType) + .getOrElse { + throw new AnalysisException( + s"ALTER COLUMN cannot find column ${quote(colName)} in v1 table. " + + s"Available: ${v1Table.schema.fieldNames.mkString(", ")}") + } + } // Add Hive type string to metadata. - val cleanedDataType = HiveStringType.replaceCharType(a.dataType.get) - if (a.dataType.get != cleanedDataType) { - builder.putString(HIVE_TYPE_STRING, a.dataType.get.catalogString) + val cleanedDataType = HiveStringType.replaceCharType(dataType) + if (dataType != cleanedDataType) { + builder.putString(HIVE_TYPE_STRING, dataType.catalogString) } val newColumn = StructField( - a.column(0), + colName, cleanedDataType, nullable = true, builder.build()) - AlterTableChangeColumnCommand(tbl.asTableIdentifier, a.column(0), newColumn) + AlterTableChangeColumnCommand(tbl.asTableIdentifier, colName, newColumn) }.getOrElse { val colName = a.column.toArray val typeChange = a.dataType.map { newDataType => diff --git a/sql/core/src/test/resources/sql-tests/inputs/change-column.sql b/sql/core/src/test/resources/sql-tests/inputs/change-column.sql index dd2fc66..2b57891 100644 --- a/sql/core/src/test/resources/sql-tests/inputs/change-column.sql +++ b/sql/core/src/test/resources/sql-tests/inputs/change-column.sql @@ -15,29 +15,34 @@ ALTER TABLE test_change CHANGE a TYPE STRING; DESC test_change; -- Change column position (not supported yet) -ALTER TABLE test_change CHANGE a TYPE INT AFTER b; -ALTER TABLE test_change CHANGE b TYPE STRING FIRST; +ALTER TABLE test_change CHANGE a AFTER b; +ALTER TABLE test_change CHANGE b FIRST; DESC test_change; -- Change column comment -ALTER TABLE test_change CHANGE a TYPE INT COMMENT 'this is column a'; -ALTER TABLE test_change CHANGE b TYPE STRING COMMENT '#*02?`'; -ALTER TABLE test_change CHANGE c TYPE INT COMMENT ''; +ALTER TABLE test_change CHANGE a COMMENT 'this is column a'; +ALTER TABLE test_change CHANGE b COMMENT '#*02?`'; +ALTER TABLE test_change CHANGE c COMMENT ''; DESC test_change; -- Don't change anything. -ALTER TABLE test_change CHANGE a TYPE INT COMMENT 'this is column a'; +ALTER TABLE test_change CHANGE a TYPE INT; +ALTER TABLE test_change CHANGE a COMMENT 'this is column a'; DESC test_change; -- Change a invalid column ALTER TABLE test_change CHANGE invalid_col TYPE INT; DESC test_change; +-- Check case insensitivity. +ALTER TABLE test_change CHANGE A COMMENT 'case insensitivity'; +DESC test_change; + -- Change column can't apply to a temporary/global_temporary view CREATE TEMPORARY VIEW temp_view(a, b) AS SELECT 1, "one"; -ALTER TABLE temp_view CHANGE a TYPE INT COMMENT 'this is column a'; +ALTER TABLE temp_view CHANGE a TYPE INT; CREATE GLOBAL TEMPORARY VIEW global_temp_view(a, b) AS SELECT 1, "one"; -ALTER TABLE global_temp.global_temp_view CHANGE a TYPE INT COMMENT 'this is column a'; +ALTER TABLE global_temp.global_temp_view CHANGE a TYPE INT; -- DROP TEST TABLE DROP TABLE test_change; diff --git a/sql/core/src/test/resources/sql-tests/results/change-column.sql.out b/sql/core/src/test/resources/sql-tests/results/change-column.sql.out index 5bb00e0..b1a32ad 100644 --- a/sql/core/src/test/resources/sql-tests/results/change-column.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/change-column.sql.out @@ -1,5 +1,5 @@ -- Automatically generated by SQLQueryTestSuite --- Number of queries: 25 +-- Number of queries: 28 -- !query @@ -27,7 +27,7 @@ struct<> -- !query output org.apache.spark.sql.catalyst.parser.ParseException -Operation not allowed: ALTER TABLE table CHANGE COLUMN requires a TYPE or a COMMENT or a FIRST/AFTER(line 1, pos 0) +Operation not allowed: ALTER TABLE table CHANGE COLUMN requires a TYPE, a SET/DROP, a COMMENT, or a FIRST/AFTER(line 1, pos 0) == SQL == ALTER TABLE test_change CHANGE a @@ -83,7 +83,7 @@ c int -- !query -ALTER TABLE test_change CHANGE a TYPE INT AFTER b +ALTER TABLE test_change CHANGE a AFTER b -- !query schema struct<> -- !query output @@ -92,7 +92,7 @@ ALTER COLUMN ... FIRST | ALTER is only supported with v2 tables.; -- !query -ALTER TABLE test_change CHANGE b TYPE STRING FIRST +ALTER TABLE test_change CHANGE b FIRST -- !query schema struct<> -- !query output @@ -111,7 +111,7 @@ c int -- !query -ALTER TABLE test_change CHANGE a TYPE INT COMMENT 'this is column a' +ALTER TABLE test_change CHANGE a COMMENT 'this is column a' -- !query schema struct<> -- !query output @@ -119,7 +119,7 @@ struct<> -- !query -ALTER TABLE test_change CHANGE b TYPE STRING COMMENT '#*02?`' +ALTER TABLE test_change CHANGE b COMMENT '#*02?`' -- !query schema struct<> -- !query output @@ -127,7 +127,7 @@ struct<> -- !query -ALTER TABLE test_change CHANGE c TYPE INT COMMENT '' +ALTER TABLE test_change CHANGE c COMMENT '' -- !query schema struct<> -- !query output @@ -145,7 +145,15 @@ c int -- !query -ALTER TABLE test_change CHANGE a TYPE INT COMMENT 'this is column a' +ALTER TABLE test_change CHANGE a TYPE INT +-- !query schema +struct<> +-- !query output + + + +-- !query +ALTER TABLE test_change CHANGE a COMMENT 'this is column a' -- !query schema struct<> -- !query output @@ -182,6 +190,24 @@ c int -- !query +ALTER TABLE test_change CHANGE A COMMENT 'case insensitivity' +-- !query schema +struct<> +-- !query output + + + +-- !query +DESC test_change +-- !query schema +struct<col_name:string,data_type:string,comment:string> +-- !query output +a int case insensitivity +b string #*02?` +c int + + +-- !query CREATE TEMPORARY VIEW temp_view(a, b) AS SELECT 1, "one" -- !query schema struct<> @@ -190,7 +216,7 @@ struct<> -- !query -ALTER TABLE temp_view CHANGE a TYPE INT COMMENT 'this is column a' +ALTER TABLE temp_view CHANGE a TYPE INT -- !query schema struct<> -- !query output @@ -207,7 +233,7 @@ struct<> -- !query -ALTER TABLE global_temp.global_temp_view CHANGE a TYPE INT COMMENT 'this is column a' +ALTER TABLE global_temp.global_temp_view CHANGE a TYPE INT -- !query schema struct<> -- !query output diff --git a/sql/core/src/test/scala/org/apache/spark/sql/connector/AlterTableTests.scala b/sql/core/src/test/scala/org/apache/spark/sql/connector/AlterTableTests.scala index 3cdac59..420cb01 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/connector/AlterTableTests.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/connector/AlterTableTests.scala @@ -651,19 +651,6 @@ trait AlterTableTests extends SharedSparkSession { } } - test("AlterTable: update column type and comment") { - val t = s"${catalogAndNamespace}table_name" - withTable(t) { - sql(s"CREATE TABLE $t (id int) USING $v2Format") - sql(s"ALTER TABLE $t ALTER COLUMN id TYPE bigint COMMENT 'doc'") - - val table = getTableMetadata(t) - - assert(table.name === fullTableName(t)) - assert(table.schema === StructType(Seq(StructField("id", LongType).withComment("doc")))) - } - } - test("AlterTable: update nested column comment") { val t = s"${catalogAndNamespace}table_name" withTable(t) { diff --git a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLSuite.scala index 913cd80..31e0078 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLSuite.scala @@ -188,7 +188,7 @@ class InMemoryCatalogedDDLSuite extends DDLSuite with SharedSparkSession { withTable("t") { sql("CREATE TABLE t(i INT) USING parquet") val e = intercept[AnalysisException] { - sql("ALTER TABLE t ALTER COLUMN i TYPE INT FIRST") + sql("ALTER TABLE t ALTER COLUMN i FIRST") } assert(e.message.contains("ALTER COLUMN ... FIRST | ALTER is only supported with v2 tables")) } @@ -1786,7 +1786,8 @@ abstract class DDLSuite extends QueryTest with SQLTestUtils { column.map(_.metadata).getOrElse(Metadata.empty) } // Ensure that change column will preserve other metadata fields. - sql("ALTER TABLE dbx.tab1 CHANGE COLUMN col1 TYPE INT COMMENT 'this is col1'") + sql("ALTER TABLE dbx.tab1 CHANGE COLUMN col1 TYPE INT") + sql("ALTER TABLE dbx.tab1 CHANGE COLUMN col1 COMMENT 'this is col1'") assert(getMetadata("col1").getString("key") == "value") assert(getMetadata("col1").getString("comment") == "this is col1") } diff --git a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/PlanResolutionSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/PlanResolutionSuite.scala index 88f3035..d439e5b 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/PlanResolutionSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/PlanResolutionSuite.scala @@ -1013,27 +1013,29 @@ class PlanResolutionSuite extends AnalysisTest { Seq("v1Table" -> true, "v2Table" -> false, "testcat.tab" -> false).foreach { case (tblName, useV1Command) => val sql1 = s"ALTER TABLE $tblName ALTER COLUMN i TYPE bigint" - val sql2 = s"ALTER TABLE $tblName ALTER COLUMN i TYPE bigint COMMENT 'new comment'" - val sql3 = s"ALTER TABLE $tblName ALTER COLUMN i COMMENT 'new comment'" + val sql2 = s"ALTER TABLE $tblName ALTER COLUMN i COMMENT 'new comment'" val parsed1 = parseAndResolve(sql1) val parsed2 = parseAndResolve(sql2) val tableIdent = TableIdentifier(tblName, None) if (useV1Command) { + val oldColumn = StructField("i", IntegerType) val newColumn = StructField("i", LongType) val expected1 = AlterTableChangeColumnCommand( tableIdent, "i", newColumn) val expected2 = AlterTableChangeColumnCommand( - tableIdent, "i", newColumn.withComment("new comment")) + tableIdent, "i", oldColumn.withComment("new comment")) comparePlans(parsed1, expected1) comparePlans(parsed2, expected2) + val sql3 = s"ALTER TABLE $tblName ALTER COLUMN j COMMENT 'new comment'" val e1 = intercept[AnalysisException] { parseAndResolve(sql3) } - assert(e1.getMessage.contains("ALTER COLUMN with v1 tables must specify new data type")) + assert(e1.getMessage.contains( + "ALTER COLUMN cannot find column j in v1 table. Available: i, s")) val sql4 = s"ALTER TABLE $tblName ALTER COLUMN a.b.c TYPE bigint" val e2 = intercept[AnalysisException] { @@ -1051,8 +1053,6 @@ class PlanResolutionSuite extends AnalysisTest { val parsed5 = parseAndResolve(sql5) comparePlans(parsed5, expected5) } else { - val parsed3 = parseAndResolve(sql3) - parsed1 match { case AlterTable(_, _, _: DataSourceV2Relation, changes) => assert(changes == Seq( @@ -1063,18 +1063,41 @@ class PlanResolutionSuite extends AnalysisTest { parsed2 match { case AlterTable(_, _, _: DataSourceV2Relation, changes) => assert(changes == Seq( - TableChange.updateColumnType(Array("i"), LongType), TableChange.updateColumnComment(Array("i"), "new comment"))) case _ => fail("expect AlterTable") } + } + } + } - parsed3 match { - case AlterTable(_, _, _: DataSourceV2Relation, changes) => - assert(changes == Seq( - TableChange.updateColumnComment(Array("i"), "new comment"))) - case _ => fail("expect AlterTable") + test("alter table: alter column action is not specified") { + val e = intercept[AnalysisException] { + parseAndResolve("ALTER TABLE v1Table ALTER COLUMN i") + } + assert(e.getMessage.contains( + "ALTER TABLE table ALTER COLUMN requires a TYPE, a SET/DROP, a COMMENT, or a FIRST/AFTER")) + } + + test("alter table: alter column case sensitivity for v1 table") { + val tblName = "v1Table" + Seq(true, false).foreach { caseSensitive => + withSQLConf(SQLConf.CASE_SENSITIVE.key -> caseSensitive.toString) { + val sql = s"ALTER TABLE $tblName ALTER COLUMN I COMMENT 'new comment'" + if (caseSensitive) { + val e = intercept[AnalysisException] { + parseAndResolve(sql) } + assert(e.getMessage.contains( + "ALTER COLUMN cannot find column I in v1 table. Available: i, s")) + } else { + val actual = parseAndResolve(sql) + val expected = AlterTableChangeColumnCommand( + TableIdentifier(tblName, None), + "I", + StructField("I", IntegerType).withComment("new comment")) + comparePlans(actual, expected) } + } } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@spark.apache.org For additional commands, e-mail: commits-h...@spark.apache.org