Skip to main content

PASSES

Static PASSES 

Source
pub static PASSES: [&(dyn Pass + Sync); 5]
Expand description

The passes, in the order they run.

A fixed sequence rather than a loop to a fixed point, which is what spec/09-optimizer.md section 9.1 asks for and what DuckDB does. A fixed point is easy to write and hard to bound: a pair of passes that undo each other runs forever, and the version that stops after a few rounds has a plan that depends on how many rounds it was given.

Folding is before pruning because folding removes column references and pruning drops the columns nothing refers to, so a CASE WHEN false THEN t.a ELSE 1 END costs a column read when the two run the other way around. Nothing in the other direction is given up: pruning drops columns and renumbers bindings, and neither of those makes anything foldable.

Filter pushdown goes between them. After folding, because a predicate that folds to a constant is a predicate with nothing to push and the pass that moves it should not be the one that finds out. Before pruning, because moving a filter below a projection rewrites it in terms of columns the projection reads, and pruning has to see the plan after the move or it drops a column that something now refers to.

Empty result pullup is after filter pushdown, because pushdown is what moves an unsatisfiable predicate down to the scan it should stop and what drops the conjuncts that were always true, so the pass that looks for a predicate nothing can satisfy should look after that has happened. It is before pruning for the same reason folding is: the subtrees it removes are subtrees pruning would otherwise walk and work out column lists for.

Top N is last, because it is the one pass that fuses two operators into one rather than moving something around. Everything before it is written against a sort and a limit, and a pass that had to know about both spellings of the same plan is a pass with two of every rule in it.