@@ -49,11 +49,14 @@ object Optimizer extends RuleExecutor[LogicalPlan] {
4949object ColumnPruning extends Rule [LogicalPlan ] {
5050 def apply (plan : LogicalPlan ): LogicalPlan = plan transform {
5151 case a @ Aggregate (_, _, child) if (child.outputSet -- a.references).nonEmpty =>
52+ // Project away references that are not needed to calculate the required aggregates.
5253 a.copy(child = Project (a.references.toSeq, child))
5354
5455 case Project (projectList, Join (left, right, joinType, condition)) =>
56+ // Collect the list of off references required either above or to evaluate the condition.
5557 val allReferences : Set [Attribute ] =
5658 projectList.flatMap(_.references).toSet ++ condition.map(_.references).getOrElse(Set .empty)
59+ /** Applies a projection when the child is producing unnecessary attributes */
5760 def prunedChild (c : LogicalPlan ) =
5861 if ((allReferences.filter(c.outputSet.contains) -- c.outputSet).nonEmpty) {
5962 Project (allReferences.filter(c.outputSet.contains).toSeq, c)
@@ -64,10 +67,16 @@ object ColumnPruning extends Rule[LogicalPlan] {
6467 Project (projectList, Join (prunedChild(left), prunedChild(right), joinType, condition))
6568
6669 case Project (project1, Project (project2, child)) =>
70+ // Create a map of Aliases to their values from the child projection.
71+ // e.g., 'SELECT ... FROM (SELECT a + b AS c, d ...)' produces Map(c -> Alias(a + b, c)).
6772 val aliasMap = project2.collect {
6873 case a @ Alias (e, _) => (a.toAttribute: Expression , a)
6974 }.toMap
70- // TODO: Fix TransformBase.
75+
76+ // Substitute any attributes that are produced by the child projection, so that we safely
77+ // eliminate it.
78+ // e.g., 'SELECT c + 1 FROM (SELECT a + b AS C ...' produces 'SELECT a + b + 1 ...'
79+ // TODO: Fix TransformBase to avoid the cast below.
7180 val substitutedProjection = project1.map(_.transform {
7281 case a if aliasMap.contains(a) => aliasMap(a)
7382 }).asInstanceOf [Seq [NamedExpression ]]
0 commit comments