Skip to content

Commit 2645d4f

Browse files
Constant Folding(null propagation)
1 parent 3d9fb09 commit 2645d4f

File tree

2 files changed

+49
-2
lines changed

2 files changed

+49
-2
lines changed

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/predicates.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ abstract class BinaryPredicate extends BinaryExpression with Predicate {
6565
def nullable = left.nullable || right.nullable
6666
}
6767

68-
case class Not(child: Expression) extends Predicate with trees.UnaryNode[Expression] {
69-
def references = child.references
68+
case class Not(child: Expression) extends UnaryExpression with Predicate {
7069
override def foldable = child.foldable
7170
def nullable = child.nullable
7271
override def toString = s"NOT $child"

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,59 @@ object ConstantFolding extends Rule[LogicalPlan] {
9494
case q: LogicalPlan => q transformExpressionsDown {
9595
// Skip redundant folding of literals.
9696
case l: Literal => l
97+
case e @ If(Literal(v, _), trueValue, falseValue) => if(v == true) trueValue else falseValue
98+
case e @ In(Literal(v, _), list) if(list.exists(c => c match {
99+
case Literal(candidate, _) if(candidate == v) => true
100+
case _ => false
101+
})) => Literal(true, BooleanType)
97102
case e if e.foldable => Literal(e.eval(null), e.dataType)
98103
}
99104
}
100105
}
101106

107+
/**
108+
* The expression may be constant value, due to one or more of its children expressions is null or
109+
* not null constantly, replaces [[catalyst.expressions.Expression Expressions]] with equivalent
110+
* [[catalyst.expressions.Literal Literal]] values if possible caused by that.
111+
*/
112+
object NullPropagation extends Rule[LogicalPlan] {
113+
def apply(plan: LogicalPlan): LogicalPlan = plan transform {
114+
case q: LogicalPlan => q transformExpressionsUp {
115+
case l: Literal => l
116+
case e @ IsNull(Literal(null, _)) => Literal(true, BooleanType)
117+
case e @ IsNull(Literal(_, _)) => Literal(false, BooleanType)
118+
case e @ IsNull(c @ Rand) => Literal(false, BooleanType)
119+
case e @ IsNotNull(Literal(null, _)) => Literal(false, BooleanType)
120+
case e @ IsNotNull(Literal(_, _)) => Literal(true, BooleanType)
121+
case e @ IsNotNull(c @ Rand) => Literal(true, BooleanType)
122+
case e @ GetItem(Literal(null, _), _) => Literal(null, e.dataType)
123+
case e @ GetItem(_, Literal(null, _)) => Literal(null, e.dataType)
124+
case e @ GetField(Literal(null, _), _) => Literal(null, e.dataType)
125+
case e @ Coalesce(children) => {
126+
val newChildren = children.filter(c => c match {
127+
case Literal(null, _) => false
128+
case _ => true
129+
})
130+
if(newChildren.length == null) {
131+
Literal(null, e.dataType)
132+
} else if(newChildren.length == children.length){
133+
e
134+
} else {
135+
Coalesce(newChildren)
136+
}
137+
}
138+
// TODO put exceptional cases(Unary & Binary Expression) before here.
139+
case e: UnaryExpression => e.child match {
140+
case Literal(null, _) => Literal(null, e.dataType)
141+
}
142+
case e: BinaryExpression => e.children match {
143+
case Literal(null, _) :: right :: Nil => Literal(null, e.dataType)
144+
case left :: Literal(null, _) :: Nil => Literal(null, e.dataType)
145+
}
146+
}
147+
}
148+
}
149+
102150
/**
103151
* Simplifies boolean expressions where the answer can be determined without evaluating both sides.
104152
* Note that this rule can eliminate expressions that might otherwise have been evaluated and thus

0 commit comments

Comments
 (0)