Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -507,14 +507,19 @@ class AstBuilder extends SqlBaseParserBaseVisitor[AnyRef] with SQLConfHelper wit
ctx: PartitionSpecContext): Map[String, Option[String]] = withOrigin(ctx) {
val legacyNullAsString =
conf.getConf(SQLConf.LEGACY_PARSE_NULL_PARTITION_SPEC_AS_STRING_LITERAL)
val keepPartitionTypeAsString =
conf.getConf(SQLConf.LEGACY_KEEP_PARTITION_SPEC_AS_STRING_LITERAL)

val parts = ctx.partitionVal.asScala.map { pVal =>
// Check if the query attempted to refer to a DEFAULT column value within the PARTITION clause
// and return a specific error to help guide the user, since this is not allowed.
if (pVal.DEFAULT != null) {
throw QueryParsingErrors.defaultColumnReferencesNotAllowedInPartitionSpec(ctx)
}
val name = pVal.identifier.getText
val value = Option(pVal.constant).map(v => visitStringConstant(v, legacyNullAsString))
val value = Option(pVal.constant).map(v => {
visitStringConstant(v, legacyNullAsString, keepPartitionTypeAsString)
})
name -> value
}
// Before calling `toMap`, we check duplicated keys to avoid silently ignore partition values
Expand Down Expand Up @@ -546,14 +551,19 @@ class AstBuilder extends SqlBaseParserBaseVisitor[AnyRef] with SQLConfHelper wit
*/
protected def visitStringConstant(
ctx: ConstantContext,
legacyNullAsString: Boolean): String = withOrigin(ctx) {
legacyNullAsString: Boolean,
keepPartitionTypeAsString: Boolean): String = withOrigin(ctx) {
expression(ctx) match {
case Literal(null, _) if !legacyNullAsString => null
case l @ Literal(null, _) => l.toString
case l: Literal =>
// TODO For v2 commands, we will cast the string back to its actual value,
// which is a waste and can be improved in the future.
Cast(l, StringType, Some(conf.sessionLocalTimeZone)).eval().toString
if (keepPartitionTypeAsString && !ctx.isInstanceOf[StringLiteralContext]) {
ctx.getText
} else {
// TODO For v2 commands, we will cast the string back to its actual value,
// which is a waste and can be improved in the future.
Cast(l, StringType, Some(conf.sessionLocalTimeZone)).eval().toString
}
case other =>
throw new IllegalArgumentException(s"Only literals are allowed in the " +
s"partition spec, but got ${other.sql}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4059,6 +4059,15 @@ object SQLConf {
.booleanConf
.createWithDefault(true)

val LEGACY_KEEP_PARTITION_SPEC_AS_STRING_LITERAL =
buildConf("spark.sql.legacy.keepPartitionSpecAsStringLiteral")
.internal()
.doc("If it is set to true and the type of the partition is string, " +
"partition value will be treated as string value but not numeric value")
.version("3.4.0")
.booleanConf
.createWithDefault(false)

/**
* Holds information about keys that have been deprecated.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,8 @@ class SparkSqlAstBuilder extends AstBuilder {
* Convert a constants list into a String sequence.
*/
override def visitConstantList(ctx: ConstantListContext): Seq[String] = withOrigin(ctx) {
ctx.constant.asScala.map(v => visitStringConstant(v, legacyNullAsString = false)).toSeq
ctx.constant.asScala.map(v => visitStringConstant(v,
legacyNullAsString = false, keepPartitionTypeAsString = false)).toSeq
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,36 @@ trait SQLInsertTestSuite extends QueryTest with SQLTestUtils {
}
}
}

test("SPARK-41982: When the partition is not enclosed with quotation marks, " +
"the partition type is string and keepPartitionSpecAsStringLiteral is enabled, " +
"we need to treat it as a string type partition") {
withSQLConf(SQLConf.LEGACY_KEEP_PARTITION_SPEC_AS_STRING_LITERAL.key -> "true") {
withTable("t") {
sql("create table t(i string, j int) using orc partitioned by (dt string)")
sql("insert into t partition(dt=08) values('a', 10)")
Seq(
"select * from t where dt='08'",
"select * from t where dt=08"
).foreach { query =>
checkAnswer(sql(query), Seq(Row("a", 10, "08")))
}
val e = intercept[AnalysisException](sql("alter table t drop partition(dt='8')"))
assert(e.getMessage.contains("PARTITIONS_NOT_FOUND"))
}
}

withSQLConf(SQLConf.LEGACY_KEEP_PARTITION_SPEC_AS_STRING_LITERAL.key -> "false") {
withTable("t") {
sql("create table t(i string, j int) using orc partitioned by (dt string)")
sql("insert into t partition(dt=08) values('a', 10)")
checkAnswer(sql("select * from t where dt='08'"), sql("select * from t where dt='07'"))
checkAnswer(sql("select * from t where dt=08"), Seq(Row("a", 10, "8")))
val e = intercept[AnalysisException](sql("alter table t drop partition(dt='08')"))
assert(e.getMessage.contains("PARTITIONS_NOT_FOUND"))
}
}
}
}

class FileSourceSQLInsertTestSuite extends SQLInsertTestSuite with SharedSparkSession {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,4 +257,26 @@ trait AlterTableAddPartitionSuiteBase extends QueryTest with DDLCommandTestUtils
}
}
}

test("SPARK-41982: add partition when keepPartitionTypeAsString set `true`") {
withSQLConf(SQLConf.LEGACY_KEEP_PARTITION_SPEC_AS_STRING_LITERAL.key -> "true") {
withNamespaceAndTable("ns", "tbl") { t =>
sql(s"CREATE TABLE $t(name STRING, age INT) USING PARQUET PARTITIONED BY (dt STRING)")
sql(s"ALTER TABLE $t ADD PARTITION(dt = 08)")
checkPartitions(t, Map("dt" -> "08"))
sql(s"ALTER TABLE $t ADD PARTITION(dt = '09')")
checkPartitions(t, Map("dt" -> "09"), Map("dt" -> "08"))
}
}

withSQLConf(SQLConf.LEGACY_KEEP_PARTITION_SPEC_AS_STRING_LITERAL.key -> "false") {
withNamespaceAndTable("ns", "tb2") { t =>
sql(s"CREATE TABLE $t(name STRING, age INT) USING PARQUET PARTITIONED BY (dt STRING)")
sql(s"ALTER TABLE $t ADD PARTITION(dt = 08)")
checkPartitions(t, Map("dt" -> "8"))
sql(s"ALTER TABLE $t ADD PARTITION(dt = '09')")
checkPartitions(t, Map("dt" -> "09"), Map("dt" -> "8"))
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -254,4 +254,34 @@ trait AlterTableDropPartitionSuiteBase extends QueryTest with DDLCommandTestUtil
checkPartitions(t)
}
}

test("SPARK-41982: drop partition when keepPartitionTypeAsString set `true`") {
withSQLConf(SQLConf.LEGACY_KEEP_PARTITION_SPEC_AS_STRING_LITERAL.key -> "true") {
withNamespaceAndTable("ns", "tbl") { t =>
sql(s"CREATE TABLE $t(name STRING, age INT) using orc PARTITIONED BY (dt STRING)")
sql(s"ALTER TABLE $t ADD PARTITION(dt = 08)")
checkPartitions(t, Map("dt" -> "08"))
sql(s"ALTER TABLE $t DROP PARTITION (dt = 08)")
checkPartitions(t)
sql(s"ALTER TABLE $t ADD PARTITION(dt = '08')")
checkPartitions(t, Map("dt" -> "08"))
sql(s"ALTER TABLE $t DROP PARTITION (dt = '08')")
checkPartitions(t)
}
}

withSQLConf(SQLConf.LEGACY_KEEP_PARTITION_SPEC_AS_STRING_LITERAL.key -> "false") {
withNamespaceAndTable("ns", "tb2") { t =>
sql(s"CREATE TABLE $t(name STRING, age INT) using orc PARTITIONED BY (dt STRING)")
sql(s"ALTER TABLE $t ADD PARTITION(dt = 08)")
checkPartitions(t, Map("dt" -> "8"))
sql(s"ALTER TABLE $t DROP PARTITION (dt = 08)")
checkPartitions(t)
sql(s"ALTER TABLE $t ADD PARTITION(dt = 08)")
checkPartitions(t, Map("dt" -> "8"))
sql(s"ALTER TABLE $t DROP PARTITION (dt = 8)")
checkPartitions(t)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -242,4 +242,40 @@ trait AlterTableRenamePartitionSuiteBase extends QueryTest with DDLCommandTestUt
checkPartitions(t, Map("part" -> "2020-01-02"))
}
}

test("SPARK-41982: rename partition when keepPartitionTypeAsString set `true`") {
withSQLConf(SQLConf.LEGACY_KEEP_PARTITION_SPEC_AS_STRING_LITERAL.key -> "true") {
withNamespaceAndTable("ns", "tbl") { t =>
sql(s"CREATE TABLE $t(name STRING, age INT) USING PARQUET PARTITIONED BY (dt STRING)")
sql(s"ALTER TABLE $t ADD PARTITION(dt = 08)")
checkPartitions(t, Map("dt" -> "08"))
sql(s"ALTER TABLE $t PARTITION (dt = 08)" +
s" RENAME TO PARTITION (dt = 09)")
checkPartitions(t, Map("dt" -> "09"))
sql(s"ALTER TABLE $t PARTITION (dt = 09)" +
s" RENAME TO PARTITION (dt = '08')")
checkPartitions(t, Map("dt" -> "08"))
sql(s"ALTER TABLE $t PARTITION (dt = '08')" +
s" RENAME TO PARTITION (dt = '09')")
checkPartitions(t, Map("dt" -> "09"))
}
}

withSQLConf(SQLConf.LEGACY_KEEP_PARTITION_SPEC_AS_STRING_LITERAL.key -> "false") {
withNamespaceAndTable("ns", "tb2") { t =>
sql(s"CREATE TABLE $t(name STRING, age INT) USING PARQUET PARTITIONED BY (dt STRING)")
sql(s"ALTER TABLE $t ADD PARTITION(dt = 08)")
checkPartitions(t, Map("dt" -> "8"))
sql(s"ALTER TABLE $t PARTITION (dt = 08)" +
s" RENAME TO PARTITION (dt = 09)")
checkPartitions(t, Map("dt" -> "9"))
sql(s"ALTER TABLE $t PARTITION (dt = 09)" +
s" RENAME TO PARTITION (dt = '08')")
checkPartitions(t, Map("dt" -> "08"))
sql(s"ALTER TABLE $t PARTITION (dt = '08')" +
s" RENAME TO PARTITION (dt = '09')")
checkPartitions(t, Map("dt" -> "09"))
}
}
}
}