Skip to content

Commit 1c5739f

Browse files
committed
[SQL] Cleaned up ConstantFolding slightly.
Moved couple rules out of NullPropagation and added more comments. Author: Reynold Xin <[email protected]> Closes #1430 from rxin/sql-folding-rule and squashes the following commits: 7f9a197 [Reynold Xin] Updated documentation for ConstantFolding. 7f8cf61 [Reynold Xin] [SQL] Cleaned up ConstantFolding slightly.
1 parent df95d82 commit 1c5739f

File tree

1 file changed

+28
-17
lines changed
  • sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/optimizer

1 file changed

+28
-17
lines changed

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

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -153,27 +153,25 @@ object NullPropagation extends Rule[LogicalPlan] {
153153
case e @ GetItem(Literal(null, _), _) => Literal(null, e.dataType)
154154
case e @ GetItem(_, Literal(null, _)) => Literal(null, e.dataType)
155155
case e @ GetField(Literal(null, _), _) => Literal(null, e.dataType)
156-
case e @ Coalesce(children) => {
157-
val newChildren = children.filter(c => c match {
156+
157+
// For Coalesce, remove null literals.
158+
case e @ Coalesce(children) =>
159+
val newChildren = children.filter {
158160
case Literal(null, _) => false
159161
case _ => true
160-
})
162+
}
161163
if (newChildren.length == 0) {
162164
Literal(null, e.dataType)
163165
} else if (newChildren.length == 1) {
164166
newChildren(0)
165167
} else {
166168
Coalesce(newChildren)
167169
}
168-
}
169-
case e @ If(Literal(v, _), trueValue, falseValue) => if (v == true) trueValue else falseValue
170-
case e @ In(Literal(v, _), list) if (list.exists(c => c match {
171-
case Literal(candidate, _) if candidate == v => true
172-
case _ => false
173-
})) => Literal(true, BooleanType)
170+
174171
case e @ Substring(Literal(null, _), _, _) => Literal(null, e.dataType)
175172
case e @ Substring(_, Literal(null, _), _) => Literal(null, e.dataType)
176173
case e @ Substring(_, _, Literal(null, _)) => Literal(null, e.dataType)
174+
177175
// Put exceptional cases above if any
178176
case e: BinaryArithmetic => e.children match {
179177
case Literal(null, _) :: right :: Nil => Literal(null, e.dataType)
@@ -201,9 +199,19 @@ object NullPropagation extends Rule[LogicalPlan] {
201199
object ConstantFolding extends Rule[LogicalPlan] {
202200
def apply(plan: LogicalPlan): LogicalPlan = plan transform {
203201
case q: LogicalPlan => q transformExpressionsDown {
204-
// Skip redundant folding of literals.
202+
// Skip redundant folding of literals. This rule is technically not necessary. Placing this
203+
// here avoids running the next rule for Literal values, which would create a new Literal
204+
// object and running eval unnecessarily.
205205
case l: Literal => l
206+
207+
// Fold expressions that are foldable.
206208
case e if e.foldable => Literal(e.eval(null), e.dataType)
209+
210+
// Fold "literal in (item1, item2, ..., literal, ...)" into true directly.
211+
case In(Literal(v, _), list) if list.exists {
212+
case Literal(candidate, _) if candidate == v => true
213+
case _ => false
214+
} => Literal(true, BooleanType)
207215
}
208216
}
209217
}
@@ -233,6 +241,9 @@ object BooleanSimplification extends Rule[LogicalPlan] {
233241
case (l, Literal(false, BooleanType)) => l
234242
case (_, _) => or
235243
}
244+
245+
// Turn "if (true) a else b" into "a", and if (false) a else b" into "b".
246+
case e @ If(Literal(v, _), trueValue, falseValue) => if (v == true) trueValue else falseValue
236247
}
237248
}
238249
}
@@ -254,12 +265,12 @@ object CombineFilters extends Rule[LogicalPlan] {
254265
*/
255266
object SimplifyFilters extends Rule[LogicalPlan] {
256267
def apply(plan: LogicalPlan): LogicalPlan = plan transform {
257-
case Filter(Literal(true, BooleanType), child) =>
258-
child
259-
case Filter(Literal(null, _), child) =>
260-
LocalRelation(child.output)
261-
case Filter(Literal(false, BooleanType), child) =>
262-
LocalRelation(child.output)
268+
// If the filter condition always evaluate to true, remove the filter.
269+
case Filter(Literal(true, BooleanType), child) => child
270+
// If the filter condition always evaluate to null or false,
271+
// replace the input with an empty relation.
272+
case Filter(Literal(null, _), child) => LocalRelation(child.output, data = Seq.empty)
273+
case Filter(Literal(false, BooleanType), child) => LocalRelation(child.output, data = Seq.empty)
263274
}
264275
}
265276

@@ -301,7 +312,7 @@ object PushPredicateThroughJoin extends Rule[LogicalPlan] with PredicateHelper {
301312
/**
302313
* Splits join condition expressions into three categories based on the attributes required
303314
* to evaluate them.
304-
* @returns (canEvaluateInLeft, canEvaluateInRight, haveToEvaluateInBoth)
315+
* @return (canEvaluateInLeft, canEvaluateInRight, haveToEvaluateInBoth)
305316
*/
306317
private def split(condition: Seq[Expression], left: LogicalPlan, right: LogicalPlan) = {
307318
val (leftEvaluateCondition, rest) =

0 commit comments

Comments
 (0)