-
Notifications
You must be signed in to change notification settings - Fork 29.3k
[SPARK-14922][SPARK-17732][SQL]ALTER TABLE DROP PARTITION should support comparators #19691
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
20f658a
85fdb46
f18caeb
f79c6f4
8728d3b
9832ec5
dd5d482
b4a637c
4b5c74e
e92185c
182449b
d725fc9
defc9f1
6b18939
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -282,6 +282,27 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging | |
| parts.toMap | ||
| } | ||
|
|
||
| /** | ||
| * Create a partition filter specification. | ||
| */ | ||
| def visitPartitionFilterSpec(ctx: PartitionSpecContext): Expression = withOrigin(ctx) { | ||
| val parts = ctx.expression.asScala.map { pVal => | ||
| expression(pVal) match { | ||
| case EqualNullSafe(_, _) => | ||
| throw new ParseException("'<=>' operator is not allowed in partition specification.", ctx) | ||
| case cmp @ BinaryComparison(UnresolvedAttribute(name :: Nil), constant: Literal) => | ||
| cmp.withNewChildren(Seq(AttributeReference(name, StringType)(), constant)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it ok to pass all the type of literals here?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Either way, we might need tests for non int-literal cases.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if the partition column is not of
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. I'll work on this these days. |
||
| case _ => | ||
| throw new ParseException("Invalid partition filter specification", ctx) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it would be useful to output to the user which expression was invalid and wh |
||
| } | ||
| } | ||
| if(parts.isEmpty) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wouldn't be better to return the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why aren't we returning
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you're right. I will change this. |
||
| null | ||
| } else { | ||
| parts.reduceLeft(And) | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Create a partition specification map without optional values. | ||
| */ | ||
|
|
@@ -293,6 +314,14 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Create a partition specification map without optional values | ||
| * and a partition filter specification. | ||
| */ | ||
| protected def visitPartition(ctx: PartitionSpecContext): (Map[String, String], Expression) = { | ||
| (visitNonOptionalPartitionSpec(ctx), visitPartitionFilterSpec(ctx)) | ||
| } | ||
|
|
||
| /** | ||
| * Convert a constant of any type into a string. This is typically used in DDL commands, and its | ||
| * main purpose is to prevent slight differences due to back to back conversions i.e.: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,7 +32,7 @@ import org.apache.spark.sql.catalyst.TableIdentifier | |
| import org.apache.spark.sql.catalyst.analysis.{NoSuchTableException, Resolver} | ||
| import org.apache.spark.sql.catalyst.catalog._ | ||
| import org.apache.spark.sql.catalyst.catalog.CatalogTypes.TablePartitionSpec | ||
| import org.apache.spark.sql.catalyst.expressions.{Attribute, AttributeReference} | ||
| import org.apache.spark.sql.catalyst.expressions.{Attribute, AttributeReference, Expression, PredicateHelper} | ||
| import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan | ||
| import org.apache.spark.sql.execution.datasources.{HadoopFsRelation, LogicalRelation, PartitioningUtils} | ||
| import org.apache.spark.sql.execution.datasources.orc.OrcFileFormat | ||
|
|
@@ -515,28 +515,58 @@ case class AlterTableRenamePartitionCommand( | |
| */ | ||
| case class AlterTableDropPartitionCommand( | ||
| tableName: TableIdentifier, | ||
| specs: Seq[TablePartitionSpec], | ||
| partitions: Seq[(TablePartitionSpec, Expression)], | ||
| ifExists: Boolean, | ||
| purge: Boolean, | ||
| retainData: Boolean) | ||
| extends RunnableCommand { | ||
| extends RunnableCommand with PredicateHelper { | ||
|
|
||
| override def run(sparkSession: SparkSession): Seq[Row] = { | ||
| val catalog = sparkSession.sessionState.catalog | ||
| val table = catalog.getTableMetadata(tableName) | ||
| val resolver = sparkSession.sessionState.conf.resolver | ||
| DDLUtils.verifyAlterTableType(catalog, table, isView = false) | ||
| DDLUtils.verifyPartitionProviderIsHive(sparkSession, table, "ALTER TABLE DROP PARTITION") | ||
|
|
||
| val normalizedSpecs = specs.map { spec => | ||
| PartitioningUtils.normalizePartitionSpec( | ||
| spec, | ||
| table.partitionColumnNames, | ||
| table.identifier.quotedString, | ||
| sparkSession.sessionState.conf.resolver) | ||
| val toDrop = partitions.flatMap { partition => | ||
| val normalizedSpecs = PartitioningUtils.normalizePartitionSpec( | ||
| partition._1, | ||
| table.partitionColumnNames, | ||
| table.identifier.quotedString, | ||
| sparkSession.sessionState.conf.resolver) | ||
|
|
||
| val partitionSet = { | ||
| if (partition._2 != null) { | ||
| partition._2.references.foreach { attr => | ||
| if (!table.partitionColumnNames.exists(resolver(_, attr.name))) { | ||
| throw new AnalysisException(s"${attr.name} is not a valid partition column " + | ||
| s"in table ${table.identifier.quotedString}.") | ||
| } | ||
| } | ||
| val partitions = catalog.listPartitionsByFilter( | ||
| table.identifier, Seq(partition._2)).map(_.spec) | ||
| if (partitions.isEmpty && !ifExists) { | ||
| throw new AnalysisException(s"There is no partition for ${partition._2.sql}") | ||
| } | ||
| partitions | ||
| } else { | ||
| Seq.empty[TablePartitionSpec] | ||
| } | ||
| }.distinct | ||
|
|
||
| if (normalizedSpecs.isEmpty && partitionSet.isEmpty) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can,t we just return
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mgaido91 I tried this command in hive. And hive only dropped the intersection of two partition filter. |
||
| Seq.empty[TablePartitionSpec] | ||
| } else if (normalizedSpecs.isEmpty && !partitionSet.isEmpty) { | ||
| partitionSet | ||
| } else if (!normalizedSpecs.isEmpty && partitionSet.isEmpty) { | ||
| Seq(normalizedSpecs) | ||
| } else { | ||
| partitionSet.intersect(normalizedSpecs.toSeq) | ||
| } | ||
| } | ||
|
|
||
| catalog.dropPartitions( | ||
| table.identifier, normalizedSpecs, ignoreIfNotExists = ifExists, purge = purge, | ||
| table.identifier, toDrop, ignoreIfNotExists = ifExists, purge = purge, | ||
| retainData = retainData) | ||
|
|
||
| CommandUtils.updateTableStats(sparkSession, table) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still the same question here. Constant has to be in the right side?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hive supports them only on the right side. So it makes sense to have the same here I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we support the right-side only, it seems be useful to print explicit error messages like
left-side literal not supported ....?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can also enforce this is the syntax, like here: https://github.com/apache/spark/pull/20999/files#diff-8c1cb2af4aa1109e08481dae79052cc3R269