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

public final class SelectionMergePass extends Object
Cleanup pass that puts selections back together — the two rules that turn several filters into one.

SEL-002 — adjacent selections

σ(A)(σ(B)(R)) → σ(A ∧ B)(R). Multiple adjacent selections are collapsed in a single pass: σ(A)(σ(B)(σ(C)(R))) → σ(A ∧ B ∧ C)(R) (two firings, bottom-up). This is the inverse of SelectionSplitPass.

SEL-010 — a set operation over two selections of one input


   σ i (A)  ∪  σ q (A)   →   δ σ (i ∨ q) (A)
   σ i (A)  ∩  σ q (A)   →   δ σ (i ∧ q) (A)
   σ i (A)  −  σ q (A)   →   δ σ (i ∧ (¬q ∨ q IS UNKNOWN)) (A)
 

When both branches filter the same input, the operation is doing by row-matching what one predicate does by evaluation. The rewrite deletes a blocking operator outright — ∪ and ∩ each buffer a hash set of one side — and leaves one filtered read where there were two. It also restores pushdown: the SQL renderer folds σ but not UNION, so the set operation is a boundary the fold cannot cross, and one WHERE crosses it.

The two inputs are compared with AstEquivalence, which is location-free, so the same sub-expression written out twice matches where record equality never could.

Why the δ, and when it is dropped

∪ and ∩ declare MaterializationMode.SET and PropertyDeriver reports their output duplicate-free on the strength of that declaration — which DIST-001 then reads. A merged σ over a bag input does not de-duplicate, so handing one back bare would make a claim the input need not honour, and a δ removed above it would not come back. The δ is therefore emitted unless the input is provably duplicate-free, which is the same question DIST-001 asks; either way the set operation is gone.

Gates

  • Reproducibility. The rewrite evaluates the input once where the query evaluated it twice, and evaluates each predicate once per row rather than once per branch, so both branches must be deterministic (DeterminismSource on the context).
  • − is not i ∧ ¬q. A row whose q is UNKNOWN is absent from σq(A) and so kept by the difference, while ¬UNKNOWN is UNKNOWN and a bare ¬q drops it. SelectionComplement writes the correction.
  • ⊎ is excluded — bag union, so the multiplicities are the answer — and so is ∆, which would need an XOR the predicate language does not have.

Phase placement

SEL-010 is the exact inverse of SEL-009, which distributes a σ over the set operations. They are in different phases for the reason SEL-001/SEL-002 are: put both in one phase and the sweep trades the two shapes forever. SEL-009 runs in pushdown and this pass in cleanup, which is also the useful order — a σ that was distributed and could then be carried no further is merged back into one.

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