java.lang.Object
com.darkcollective.relix.optimizer.internal.SelectionPushdownPass

public final class SelectionPushdownPass extends Object
Optimization pass that moves selections (σ) closer to their source relations, reducing the number of tuples flowing through intermediate operators (SEL-003..009).

Rules applied (top-down per selection node):

  • SEL-003 — Push selection below projection when every column referenced by the predicate is present in the projection's input and not introduced as a computed alias by the projection.
  • SEL-004 — Push selection below rename, rewriting attribute references from the renamed column names to the original column names. Only applies when the rename provides a complete column-name mapping or no column renaming at all.
  • SEL-005 — Push a selection whose predicate references only one side of an inner join into that join's input. Applies to NaturalJoinNode and ThetaJoinNode (either side); LeftOuterJoinNode and SemiJoinNode and AntiJoinNode (left side only); RightOuterJoinNode (right side only). Schema annotations for both join inputs are required.
  • SEL-006 — Replicate a selection into both branches of a UnionAllNode so rows are filtered as early as possible.
  • SEL-007 — Demote a HAVING-position selection to a WHERE-position one: push the conjuncts that reference only bare-column grouping keys of an AggregationNode below it, leaving anything that touches an aggregate output as a residual σ above.
  • SEL-008 — Push a selection below a DistinctNode or a SortNode. Unconditional: both are row- and column-preserving with respect to a filter, and both are blocking, so a σ left above one deduplicates or sorts rows that are about to be discarded.
  • SEL-009 — Distribute a selection over a set operation: replicated into both branches of UnionNode, IntersectionNode, SymmetricDifferenceNode and DifferenceNode — the subtrahend included, because the same predicate goes into the minuend, so a row the filtered subtrahend stops removing is one the filtered minuend no longer offers. OuterUnionNode is deliberately excluded — its branches have different schemas, so a predicate valid against one may reference a column absent from the other — as are ÷ and ∘, neither of which is a row filter with respect to σ.

The traversal is top-down for selection nodes (try to push first, then recurse into the result) and bottom-up for all other nodes. This allows a single pass to push a selection through multiple levels in one invocation, while still processing nested trees.

A σ whose input is another σ looks through the chain: it retries against the chain's input and restores the skipped selection above the result. Without that, a pushable conjunct would be stranded whenever SelectionSplitPass happened to place a non-pushable one beneath it — σ dept = "HR" (σ SUM(pay) > 10 (γ dept, SUM(pay) (Staff))) would never reach the γ. Conjunction commutes, so swapping the two is sound.

This pass should run after SelectionSplitPass so that individual conjuncts are moveable independently.

This class is package-private and stateless; call apply(RelNode, String, SchemaAnnotations, OptimizationContext) as a static method.