@@ -26,6 +26,7 @@ import org.apache.spark.sql.catalyst.types._
26
26
object Optimizer extends RuleExecutor [LogicalPlan ] {
27
27
val batches =
28
28
Batch (" ConstantFolding" , Once ,
29
+ NullPropagation ,
29
30
ConstantFolding ,
30
31
BooleanSimplification ,
31
32
SimplifyFilters ,
@@ -87,23 +88,18 @@ object ColumnPruning extends Rule[LogicalPlan] {
87
88
88
89
/**
89
90
* Replaces [[catalyst.expressions.Expression Expressions ]] that can be statically evaluated with
90
- * equivalent [[catalyst.expressions.Literal Literal ]] values.
91
+ * equivalent [[catalyst.expressions.Literal Literal ]] values. This rule is more specific with
92
+ * Null value propagation from bottom to top of the expression tree.
91
93
*/
92
- object ConstantFolding extends Rule [LogicalPlan ] {
94
+ object NullPropagation extends Rule [LogicalPlan ] {
93
95
def apply (plan : LogicalPlan ): LogicalPlan = plan transform {
94
96
case q : LogicalPlan => q transformExpressionsUp {
95
97
// Skip redundant folding of literals.
96
98
case l : Literal => l
97
- // if it's foldable
98
- case e if e.foldable => Literal (e.eval(null ), e.dataType)
99
99
case e @ Count (Literal (null , _)) => Literal (null , e.dataType)
100
100
case e @ Sum (Literal (null , _)) => Literal (null , e.dataType)
101
101
case e @ Average (Literal (null , _)) => Literal (null , e.dataType)
102
- case e @ IsNull (Literal (null , _)) => Literal (true , BooleanType )
103
- case e @ IsNull (Literal (_, _)) => Literal (false , BooleanType )
104
102
case e @ IsNull (c @ Rand ) => Literal (false , BooleanType )
105
- case e @ IsNotNull (Literal (null , _)) => Literal (false , BooleanType )
106
- case e @ IsNotNull (Literal (_, _)) => Literal (true , BooleanType )
107
103
case e @ IsNotNull (c @ Rand ) => Literal (true , BooleanType )
108
104
case e @ GetItem (Literal (null , _), _) => Literal (null , e.dataType)
109
105
case e @ GetItem (_, Literal (null , _)) => Literal (null , e.dataType)
@@ -113,10 +109,10 @@ object ConstantFolding extends Rule[LogicalPlan] {
113
109
case Literal (null , _) => false
114
110
case _ => true
115
111
})
116
- if (newChildren.length == null ) {
112
+ if (newChildren.length == 0 ) {
117
113
Literal (null , e.dataType)
118
- } else if (newChildren.length == children.length) {
119
- e
114
+ } else if (newChildren.length == 1 ) {
115
+ newChildren( 0 )
120
116
} else {
121
117
Coalesce (newChildren)
122
118
}
@@ -126,9 +122,8 @@ object ConstantFolding extends Rule[LogicalPlan] {
126
122
case Literal (candidate, _) if (candidate == v) => true
127
123
case _ => false
128
124
})) => Literal (true , BooleanType )
129
-
130
- case e @ SortOrder (_, _) => e
131
- // put exceptional cases(Unary & Binary Expression) before here.
125
+ // Put exceptional cases(Unary & Binary Expression if it doesn't produce null with constant
126
+ // null operand) before here.
132
127
case e : UnaryExpression => e.child match {
133
128
case Literal (null , _) => Literal (null , e.dataType)
134
129
case _ => e
@@ -141,6 +136,19 @@ object ConstantFolding extends Rule[LogicalPlan] {
141
136
}
142
137
}
143
138
}
139
+ /**
140
+ * Replaces [[catalyst.expressions.Expression Expressions ]] that can be statically evaluated with
141
+ * equivalent [[catalyst.expressions.Literal Literal ]] values.
142
+ */
143
+ object ConstantFolding extends Rule [LogicalPlan ] {
144
+ def apply (plan : LogicalPlan ): LogicalPlan = plan transform {
145
+ case q : LogicalPlan => q transformExpressionsDown {
146
+ // Skip redundant folding of literals.
147
+ case l : Literal => l
148
+ case e if e.foldable => Literal (e.eval(null ), e.dataType)
149
+ }
150
+ }
151
+ }
144
152
145
153
/**
146
154
* Simplifies boolean expressions where the answer can be determined without evaluating both sides.
0 commit comments