Skip to content

Commit fa9ce1d

Browse files
aokolnychyidongjoon-hyun
authored andcommitted
[SPARK-33722][SQL] Handle DELETE in ReplaceNullWithFalseInPredicate
### What changes were proposed in this pull request? This PR adds `DeleteFromTable` to supported plans in `ReplaceNullWithFalseInPredicate`. ### Why are the changes needed? This change allows Spark to optimize delete conditions like we optimize filters. ### Does this PR introduce _any_ user-facing change? No. ### How was this patch tested? This PR extends the existing test cases to also cover `DeleteFromTable`. Closes #30688 from aokolnychyi/spark-33722. Authored-by: Anton Okolnychyi <[email protected]> Signed-off-by: Dongjoon Hyun <[email protected]>
1 parent b5399d4 commit fa9ce1d

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/optimizer/ReplaceNullWithFalseInPredicate.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ package org.apache.spark.sql.catalyst.optimizer
2020
import org.apache.spark.sql.catalyst.expressions.{And, ArrayExists, ArrayFilter, CaseWhen, Expression, If}
2121
import org.apache.spark.sql.catalyst.expressions.{LambdaFunction, Literal, MapFilter, Or}
2222
import org.apache.spark.sql.catalyst.expressions.Literal.FalseLiteral
23-
import org.apache.spark.sql.catalyst.plans.logical.{Filter, Join, LogicalPlan}
23+
import org.apache.spark.sql.catalyst.plans.logical.{DeleteFromTable, Filter, Join, LogicalPlan}
2424
import org.apache.spark.sql.catalyst.rules.Rule
2525
import org.apache.spark.sql.types.BooleanType
2626
import org.apache.spark.util.Utils
@@ -53,6 +53,7 @@ object ReplaceNullWithFalseInPredicate extends Rule[LogicalPlan] {
5353
def apply(plan: LogicalPlan): LogicalPlan = plan transform {
5454
case f @ Filter(cond, _) => f.copy(condition = replaceNullWithFalse(cond))
5555
case j @ Join(_, _, _, Some(cond), _) => j.copy(condition = Some(replaceNullWithFalse(cond)))
56+
case d @ DeleteFromTable(_, Some(cond)) => d.copy(condition = Some(replaceNullWithFalse(cond)))
5657
case p: LogicalPlan => p transformExpressions {
5758
case i @ If(pred, _, _) => i.copy(predicate = replaceNullWithFalse(pred))
5859
case cw @ CaseWhen(branches, _) =>

sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/optimizer/ReplaceNullWithFalseInPredicateSuite.scala

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import org.apache.spark.sql.catalyst.dsl.plans._
2424
import org.apache.spark.sql.catalyst.expressions.{And, ArrayExists, ArrayFilter, ArrayTransform, CaseWhen, Expression, GreaterThan, If, LambdaFunction, Literal, MapFilter, NamedExpression, Or, UnresolvedNamedLambdaVariable}
2525
import org.apache.spark.sql.catalyst.expressions.Literal.{FalseLiteral, TrueLiteral}
2626
import org.apache.spark.sql.catalyst.plans.{Inner, PlanTest}
27-
import org.apache.spark.sql.catalyst.plans.logical.{LocalRelation, LogicalPlan}
27+
import org.apache.spark.sql.catalyst.plans.logical.{DeleteFromTable, LocalRelation, LogicalPlan}
2828
import org.apache.spark.sql.catalyst.rules.RuleExecutor
2929
import org.apache.spark.sql.internal.SQLConf
3030
import org.apache.spark.sql.types.{BooleanType, IntegerType}
@@ -48,6 +48,7 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
4848
test("replace null inside filter and join conditions") {
4949
testFilter(originalCond = Literal(null, BooleanType), expectedCond = FalseLiteral)
5050
testJoin(originalCond = Literal(null, BooleanType), expectedCond = FalseLiteral)
51+
testDelete(originalCond = Literal(null, BooleanType), expectedCond = FalseLiteral)
5152
}
5253

5354
test("Not expected type - replaceNullWithFalse") {
@@ -64,6 +65,7 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
6465
Literal(null, BooleanType))
6566
testFilter(originalCond, expectedCond = FalseLiteral)
6667
testJoin(originalCond, expectedCond = FalseLiteral)
68+
testDelete(originalCond, expectedCond = FalseLiteral)
6769
}
6870

6971
test("replace nulls in nested expressions in branches of If") {
@@ -73,6 +75,7 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
7375
UnresolvedAttribute("b") && Literal(null, BooleanType))
7476
testFilter(originalCond, expectedCond = FalseLiteral)
7577
testJoin(originalCond, expectedCond = FalseLiteral)
78+
testDelete(originalCond, expectedCond = FalseLiteral)
7679
}
7780

7881
test("replace null in elseValue of CaseWhen") {
@@ -83,6 +86,7 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
8386
val expectedCond = CaseWhen(branches, FalseLiteral)
8487
testFilter(originalCond, expectedCond)
8588
testJoin(originalCond, expectedCond)
89+
testDelete(originalCond, expectedCond)
8690
}
8791

8892
test("replace null in branch values of CaseWhen") {
@@ -92,6 +96,7 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
9296
val originalCond = CaseWhen(branches, Literal(null))
9397
testFilter(originalCond, expectedCond = FalseLiteral)
9498
testJoin(originalCond, expectedCond = FalseLiteral)
99+
testDelete(originalCond, expectedCond = FalseLiteral)
95100
}
96101

97102
test("replace null in branches of If inside CaseWhen") {
@@ -108,6 +113,7 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
108113

109114
testFilter(originalCond, expectedCond)
110115
testJoin(originalCond, expectedCond)
116+
testDelete(originalCond, expectedCond)
111117
}
112118

113119
test("replace null in complex CaseWhen expressions") {
@@ -127,19 +133,22 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
127133

128134
testFilter(originalCond, expectedCond)
129135
testJoin(originalCond, expectedCond)
136+
testDelete(originalCond, expectedCond)
130137
}
131138

132139
test("replace null in Or") {
133140
val originalCond = Or(UnresolvedAttribute("b"), Literal(null))
134141
val expectedCond = UnresolvedAttribute("b")
135142
testFilter(originalCond, expectedCond)
136143
testJoin(originalCond, expectedCond)
144+
testDelete(originalCond, expectedCond)
137145
}
138146

139147
test("replace null in And") {
140148
val originalCond = And(UnresolvedAttribute("b"), Literal(null))
141149
testFilter(originalCond, expectedCond = FalseLiteral)
142150
testJoin(originalCond, expectedCond = FalseLiteral)
151+
testDelete(originalCond, expectedCond = FalseLiteral)
143152
}
144153

145154
test("replace nulls in nested And/Or expressions") {
@@ -148,6 +157,7 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
148157
Or(Literal(null), And(Literal(null), And(UnresolvedAttribute("b"), Literal(null)))))
149158
testFilter(originalCond, expectedCond = FalseLiteral)
150159
testJoin(originalCond, expectedCond = FalseLiteral)
160+
testDelete(originalCond, expectedCond = FalseLiteral)
151161
}
152162

153163
test("replace null in And inside branches of If") {
@@ -157,6 +167,7 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
157167
And(UnresolvedAttribute("b"), Literal(null, BooleanType)))
158168
testFilter(originalCond, expectedCond = FalseLiteral)
159169
testJoin(originalCond, expectedCond = FalseLiteral)
170+
testDelete(originalCond, expectedCond = FalseLiteral)
160171
}
161172

162173
test("replace null in branches of If inside And") {
@@ -168,6 +179,7 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
168179
And(FalseLiteral, UnresolvedAttribute("b"))))
169180
testFilter(originalCond, expectedCond = FalseLiteral)
170181
testJoin(originalCond, expectedCond = FalseLiteral)
182+
testDelete(originalCond, expectedCond = FalseLiteral)
171183
}
172184

173185
test("replace null in branches of If inside another If") {
@@ -177,13 +189,15 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
177189
Literal(null))
178190
testFilter(originalCond, expectedCond = FalseLiteral)
179191
testJoin(originalCond, expectedCond = FalseLiteral)
192+
testDelete(originalCond, expectedCond = FalseLiteral)
180193
}
181194

182195
test("replace null in CaseWhen inside another CaseWhen") {
183196
val nestedCaseWhen = CaseWhen(Seq(UnresolvedAttribute("b") -> FalseLiteral), Literal(null))
184197
val originalCond = CaseWhen(Seq(nestedCaseWhen -> TrueLiteral), Literal(null))
185198
testFilter(originalCond, expectedCond = FalseLiteral)
186199
testJoin(originalCond, expectedCond = FalseLiteral)
200+
testDelete(originalCond, expectedCond = FalseLiteral)
187201
}
188202

189203
test("inability to replace null in non-boolean branches of If") {
@@ -196,6 +210,7 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
196210
FalseLiteral)
197211
testFilter(originalCond = condition, expectedCond = condition)
198212
testJoin(originalCond = condition, expectedCond = condition)
213+
testDelete(originalCond = condition, expectedCond = condition)
199214
}
200215

201216
test("inability to replace null in non-boolean values of CaseWhen") {
@@ -210,6 +225,7 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
210225
val condition = CaseWhen(branches)
211226
testFilter(originalCond = condition, expectedCond = condition)
212227
testJoin(originalCond = condition, expectedCond = condition)
228+
testDelete(originalCond = condition, expectedCond = condition)
213229
}
214230

215231
test("inability to replace null in non-boolean branches of If inside another If") {
@@ -222,6 +238,7 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
222238
FalseLiteral)
223239
testFilter(originalCond = condition, expectedCond = condition)
224240
testJoin(originalCond = condition, expectedCond = condition)
241+
testDelete(originalCond = condition, expectedCond = condition)
225242
}
226243

227244
test("replace null in If used as a join condition") {
@@ -353,6 +370,10 @@ class ReplaceNullWithFalseInPredicateSuite extends PlanTest {
353370
test((rel, exp) => rel.select(exp), originalExpr, expectedExpr)
354371
}
355372

373+
private def testDelete(originalCond: Expression, expectedCond: Expression): Unit = {
374+
test((rel, expr) => DeleteFromTable(rel, Some(expr)), originalCond, expectedCond)
375+
}
376+
356377
private def testHigherOrderFunc(
357378
argument: Expression,
358379
createExpr: (Expression, Expression) => Expression,

0 commit comments

Comments
 (0)