Skip to content

Commit 303d640

Browse files
cloud-fanscottsand-db
authored andcommitted
Allow altering column type with char/varchar to follow the Apache Spark behavior
Today we can't alter a char/varchar column of a Delta table to a different but compatible char/varchar type. This is too strict and we should follow Apache Spark to allow it. GitOrigin-RevId: 84e5550457edfe4075dfd130d689302679f82e8e
1 parent c1f3b37 commit 303d640

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

core/src/main/scala/org/apache/spark/sql/delta/commands/alterDeltaTableCommands.scala

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import org.apache.spark.sql.catalyst.analysis.{Resolver, UnresolvedAttribute}
3434
import org.apache.spark.sql.catalyst.catalog.CatalogUtils
3535
import org.apache.spark.sql.catalyst.expressions._
3636
import org.apache.spark.sql.catalyst.plans.logical.{IgnoreCachedData, QualifiedColType}
37+
import org.apache.spark.sql.catalyst.util.CharVarcharUtils
3738
import org.apache.spark.sql.connector.catalog.TableCatalog
3839
import org.apache.spark.sql.connector.catalog.TableChange.{After, ColumnPosition, First}
3940
import org.apache.spark.sql.execution.command.LeafRunnableCommand
@@ -490,14 +491,19 @@ case class AlterTableChangeColumnDeltaCommand(
490491
throw DeltaErrors.cannotUpdateOtherField(table.name(), o)
491492
}
492493

493-
if (SchemaUtils.canChangeDataType(originalField.dataType, newColumn.dataType, resolver,
494+
// Analyzer already validates the char/varchar type change of ALTER COLUMN in
495+
// `CheckAnalysis.checkAlterTableCommand`. We should normalize char/varchar type to string type
496+
// first (original data type is already normalized as we store char/varchar as string type with
497+
// special metadata in the Delta log), then apply Delta-specific checks.
498+
val newType = CharVarcharUtils.replaceCharVarcharWithString(newColumn.dataType)
499+
if (SchemaUtils.canChangeDataType(originalField.dataType, newType, resolver,
494500
txn.metadata.columnMappingMode, columnPath :+ originalField.name).nonEmpty) {
495501
throw DeltaErrors.alterTableChangeColumnException(
496502
s"'${UnresolvedAttribute(columnPath :+ originalField.name).name}' with type " +
497503
s"'${originalField.dataType}" +
498504
s" (nullable = ${originalField.nullable})'",
499505
s"'${UnresolvedAttribute(Seq(newColumn.name)).name}' with type " +
500-
s"'${newColumn.dataType}" +
506+
s"'$newType" +
501507
s" (nullable = ${newColumn.nullable})'")
502508
}
503509

core/src/test/scala/org/apache/spark/sql/delta/DeltaAlterTableTests.scala

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@ import org.apache.hadoop.fs.Path
2929
import org.apache.spark.sql.{AnalysisException, DataFrame, QueryTest, Row}
3030
import org.apache.spark.sql.catalyst.TableIdentifier
3131
import org.apache.spark.sql.catalyst.parser.ParseException
32+
import org.apache.spark.sql.catalyst.util.CharVarcharUtils
3233
import org.apache.spark.sql.functions._
3334
import org.apache.spark.sql.internal.SQLConf
3435
import org.apache.spark.sql.test.SharedSparkSession
35-
import org.apache.spark.sql.types.{ArrayType, IntegerType, MapType, StringType, StructType}
36+
import org.apache.spark.sql.types._
3637
import org.apache.spark.util.Utils
3738

3839
trait DeltaAlterTableTestBase
@@ -1370,6 +1371,42 @@ trait DeltaAlterTableTests extends DeltaAlterTableTestBase {
13701371
}
13711372
}
13721373
}
1374+
1375+
test("CHANGE COLUMN: allow to change change column from char to string type") {
1376+
withTable("t") {
1377+
sql("CREATE TABLE t(i STRING, c CHAR(4)) USING delta")
1378+
sql("ALTER TABLE t CHANGE COLUMN c TYPE STRING")
1379+
assert(spark.table("t").schema(1).dataType === StringType)
1380+
}
1381+
}
1382+
1383+
private def checkColType(f: StructField, dt: DataType): Unit = {
1384+
assert(f.dataType == CharVarcharUtils.replaceCharVarcharWithString(dt))
1385+
assert(CharVarcharUtils.getRawType(f.metadata).contains(dt))
1386+
}
1387+
1388+
test("CHANGE COLUMN: allow to change column from char(x) to varchar(y) type x <= y") {
1389+
withTable("t") {
1390+
sql("CREATE TABLE t(i STRING, c CHAR(4)) USING delta")
1391+
sql("ALTER TABLE t CHANGE COLUMN c TYPE VARCHAR(4)")
1392+
checkColType(spark.table("t").schema(1), VarcharType(4))
1393+
}
1394+
withTable("t") {
1395+
sql("CREATE TABLE t(i STRING, c CHAR(4)) USING delta")
1396+
sql("ALTER TABLE t CHANGE COLUMN c TYPE VARCHAR(5)")
1397+
checkColType(spark.table("t").schema(1), VarcharType(5))
1398+
}
1399+
}
1400+
1401+
test("CHANGE COLUMN: allow to change column from varchar(x) to varchar(y) type x <= y") {
1402+
withTable("t") {
1403+
sql("CREATE TABLE t(i STRING, c VARCHAR(4)) USING delta")
1404+
sql("ALTER TABLE t CHANGE COLUMN c TYPE VARCHAR(4)")
1405+
checkColType(spark.table("t").schema(1), VarcharType(4))
1406+
sql("ALTER TABLE t CHANGE COLUMN c TYPE VARCHAR(5)")
1407+
checkColType(spark.table("t").schema(1), VarcharType(5))
1408+
}
1409+
}
13731410
}
13741411

13751412
trait DeltaAlterTableByNameTests extends DeltaAlterTableTests {

0 commit comments

Comments
 (0)