-
Notifications
You must be signed in to change notification settings - Fork 29.3k
[SPARK-32030][SPARK-32127][SQL] Support unlimited MATCHED and NOT MATCHED clauses in MERGE INTO #28875
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
[SPARK-32030][SPARK-32127][SQL] Support unlimited MATCHED and NOT MATCHED clauses in MERGE INTO #28875
Changes from 1 commit
e18a7a5
a6ac363
1d39c92
ab97e31
d5edef3
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 |
|---|---|---|
|
|
@@ -411,12 +411,9 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging | |
|
|
||
| val mergeCondition = expression(ctx.mergeCondition) | ||
|
|
||
| val matchedClauses = ctx.matchedClause() | ||
| if (matchedClauses.size() > 2) { | ||
| throw new ParseException("There should be at most 2 'WHEN MATCHED' clauses.", | ||
| matchedClauses.get(2)) | ||
| } | ||
| val matchedActions = matchedClauses.asScala.map { | ||
| val whenClauses = ctx.matchedOrNotMatchedClause() | ||
| val matchedClauses = whenClauses.asScala.map(_.matchedClause()).filter(_ != null) | ||
| val matchedActions = matchedClauses.map { | ||
| clause => { | ||
| if (clause.matchedAction().DELETE() != null) { | ||
| DeleteAction(Option(clause.matchedCond).map(expression)) | ||
|
|
@@ -435,12 +432,8 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging | |
| } | ||
| } | ||
| } | ||
| val notMatchedClauses = ctx.notMatchedClause() | ||
| if (notMatchedClauses.size() > 1) { | ||
| throw new ParseException("There should be at most 1 'WHEN NOT MATCHED' clause.", | ||
| notMatchedClauses.get(1)) | ||
| } | ||
| val notMatchedActions = notMatchedClauses.asScala.map { | ||
| val notMatchedClauses = whenClauses.asScala.map(_.notMatchedClause()).filter(_ != null) | ||
| val notMatchedActions = notMatchedClauses.map { | ||
| clause => { | ||
| if (clause.notMatchedAction().INSERT() != null) { | ||
| val condition = Option(clause.notMatchedCond).map(expression) | ||
|
|
@@ -468,13 +461,25 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging | |
| throw new ParseException("There must be at least one WHEN clause in a MERGE statement", ctx) | ||
| } | ||
| // children being empty means that the condition is not set | ||
| if (matchedActions.length == 2 && matchedActions.head.children.isEmpty) { | ||
| throw new ParseException("When there are 2 MATCHED clauses in a MERGE statement, " + | ||
| "the first MATCHED clause must have a condition", ctx) | ||
| } | ||
| if (matchedActions.groupBy(_.getClass).mapValues(_.size).exists(_._2 > 1)) { | ||
| val matchedActionSize = matchedActions.length | ||
| if (matchedActionSize >= 2 && !matchedActions.init.forall(_.condition.nonEmpty)) { | ||
|
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. we can still write
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. I don't think so, because 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. then this is an existing bug?
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. Yes, it was a bug.
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 you send a new PR against branch 3.0 to fix this bug?
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. Submitted a pr at #28943. |
||
| throw new ParseException( | ||
| s"When there are $matchedActionSize MATCHED clauses in a MERGE statement, " + | ||
|
xy-xin marked this conversation as resolved.
Outdated
|
||
| s"${if (matchedActionSize == 2) { | ||
| "the first MATCHED clause must have a condition" | ||
| } else { | ||
| s"the first ${matchedActionSize - 1} MATCHED clauses must have conditions" | ||
| }}", ctx) | ||
| } | ||
| val notMatchedActionSize = notMatchedActions.length | ||
| if (notMatchedActionSize >= 2 && !notMatchedActions.init.forall(_.condition.nonEmpty)) { | ||
| throw new ParseException( | ||
| "UPDATE and DELETE can appear at most once in MATCHED clauses in a MERGE statement", ctx) | ||
| s"When there are $notMatchedActionSize NOT MATCHED clauses in a MERGE statement, " + | ||
|
xy-xin marked this conversation as resolved.
Outdated
|
||
| s"${if (notMatchedActionSize == 2) { | ||
| "the first NOT MATCHED clause must have a condition" | ||
| } else { | ||
| s"the first ${notMatchedActionSize - 1} NOT MATCHED clauses must have conditions" | ||
| }}", ctx) | ||
| } | ||
|
|
||
| MergeIntoTable( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -347,23 +347,23 @@ case class MergeIntoTable( | |
| } | ||
|
|
||
| sealed abstract class MergeAction( | ||
| condition: Option[Expression]) extends Expression with Unevaluable { | ||
| val condition: Option[Expression]) extends Expression with Unevaluable { | ||
|
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. to simplify the code a little bit: Then we can just write
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. done. |
||
| override def foldable: Boolean = false | ||
| override def nullable: Boolean = false | ||
| override def dataType: DataType = throw new UnresolvedException(this, "nullable") | ||
| override def children: Seq[Expression] = condition.toSeq | ||
| } | ||
|
|
||
| case class DeleteAction(condition: Option[Expression]) extends MergeAction(condition) | ||
| case class DeleteAction(override val condition: Option[Expression]) extends MergeAction(condition) | ||
|
|
||
| case class UpdateAction( | ||
| condition: Option[Expression], | ||
| override val condition: Option[Expression], | ||
| assignments: Seq[Assignment]) extends MergeAction(condition) { | ||
| override def children: Seq[Expression] = condition.toSeq ++ assignments | ||
| } | ||
|
|
||
| case class InsertAction( | ||
| condition: Option[Expression], | ||
| override val condition: Option[Expression], | ||
| assignments: Seq[Assignment]) extends MergeAction(condition) { | ||
| override def children: Seq[Expression] = condition.toSeq ++ assignments | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.