// Clause rewrite pass (port of the Rust plan/rewrite.rs, keeping only // fuse_projection_before_aggregate -- the window-count fusion belonged to // the skipped recognizer kernels): a pure-projection boundary immediately // followed by an aggregating boundary is inlined into the aggregate, so // the preceding MATCH's scan and the aggregation land in one segment.
package plan import ( ) // pureProjectionSubst is the alias -> definition substitution a pure // projection contributes when fused into the next clause: an entry per // computed or renamed column, keyed by alias. Identity pass-throughs // contribute nothing. ok=false unless the projection is a plain 1:1 map // (no DISTINCT / ORDER BY / OFFSET / LIMIT, no aggregate, every item a // bare variable or explicitly aliased, no duplicate output name). A star // projection qualifies: LET lowers to `*` plus computed aliases, the // starred columns pass through contributing no entry, and the binder // rejects an item referencing a sibling alias from the same projection, // so substituting each alias with its definition is exact. func pureProjectionSubst( *ast.Projection) (map[string]ast.Expr, bool) { if .Distinct || len(.OrderBy) > 0 || .Skip != nil || .Limit != nil { return nil, false } := map[string]ast.Expr{} := map[string]bool{} for , := range .Items { if semantics.ExprHasAgg(.Expr) { return nil, false } var string , := .Expr.(*ast.Var) switch { case .Alias != "": = .Alias case : = .Name default: // An unaliased non-variable projection has no identifier a // later clause can reference. return nil, false } if [] { return nil, false } [] = true := && .Name == if ! { [] = .Expr } } return , true } // projectionIsAggregated reports whether a projection aggregates. func projectionIsAggregated( *ast.Projection) bool { if .Star { return false } for , := range .Items { if semantics.ExprHasAgg(.Expr) { return true } } return false } // substExpr substitutes inlined aliases into e, returning the rewritten // expression; ok=false when e contains a construct this pass does not // rewrite (a subquery / scoped expression), abandoning the fusion. A // property/label test on an inlined alias is only rewritable when the // alias maps to a bare variable. func substExpr( ast.Expr, map[string]ast.Expr) (ast.Expr, bool) { switch n := .(type) { case *ast.Lit: return , true case *ast.Var: if , := [.Name]; { return , true } return , true case *ast.Prop: , := [.Var] if ! { return , true } if , := .(*ast.Var); { return &ast.Prop{Var: .Name, Key: .Key}, true } return nil, false case *ast.HasLabelExpr: , := [.Var] if ! { return , true } if , := .(*ast.Var); { return &ast.HasLabelExpr{Var: .Name, Expr: .Expr}, true } return nil, false case *ast.Unary: , := (.Expr, ) if ! { return nil, false } return &ast.Unary{Op: .Op, Expr: }, true case *ast.IsNull: , := (.Expr, ) if ! { return nil, false } return &ast.IsNull{Expr: , Negated: .Negated}, true case *ast.IsTruth: , := (.Expr, ) if ! { return nil, false } return &ast.IsTruth{Expr: , Want: .Want, Negated: .Negated}, true case *ast.IsTyped: , := (.Expr, ) if ! { return nil, false } return &ast.IsTyped{Expr: , Kind: .Kind, Negated: .Negated}, true case *ast.Binary: , := (.LHS, ) if ! { return nil, false } , := (.RHS, ) if ! { return nil, false } return &ast.Binary{Op: .Op, LHS: , RHS: }, true case *ast.In: , := (.Expr, ) if ! { return nil, false } , := (.List, ) if ! { return nil, false } return &ast.In{Expr: , List: }, true case *ast.Func: if .Star { return , true } := make([]ast.Expr, len(.Args)) for , := range .Args { , := (, ) if ! { return nil, false } [] = } return &ast.Func{Name: .Name, Distinct: .Distinct, Args: }, true case *ast.ListExpr: := make([]ast.Expr, len(.Elems)) for , := range .Elems { , := (, ) if ! { return nil, false } [] = } return &ast.ListExpr{Elems: }, true case *ast.Case: := &ast.Case{} if .Operand != nil { , := (.Operand, ) if ! { return nil, false } .Operand = } .Whens = make([]ast.CaseWhen, len(.Whens)) for , := range .Whens { , := (.Cond, ) if ! { return nil, false } , := (.Result, ) if ! { return nil, false } .Whens[] = ast.CaseWhen{Cond: , Result: } } if .Else != nil { , := (.Else, ) if ! { return nil, false } .Else = } return , true } // Subqueries and scoped expressions bind their own variables: // conservatively refuse to fuse. return nil, false } // inlineProjection rewrites the aggregating boundary by inlining subst. // Each unaliased item is pinned to its original derived name first, so // substitution never changes an output column name. ok=false abandons the // fusion. func inlineProjection( *ast.Projection, ast.Expr, map[string]ast.Expr) (*ast.With, bool) { := ast.Projection{ Star: .Star, Distinct: .Distinct, Items: make([]ast.ReturnItem, len(.Items)), OrderBy: make([]ast.SortItem, len(.OrderBy)), Skip: .Skip, Limit: .Limit, } for , := range .Items { := .Alias if == "" { = semantics.DerivedName(.Expr) } , := substExpr(.Expr, ) if ! { return nil, false } .Items[] = ast.ReturnItem{Expr: , Alias: } } for , := range .OrderBy { , := substExpr(.Expr, ) if ! { return nil, false } .OrderBy[] = ast.SortItem{Expr: , Desc: .Desc} } var ast.Expr if != nil { , := substExpr(, ) if ! { return nil, false } = } return &ast.With{Proj: , Where: }, true } // fuseTrailingProjectionIntoRet folds a final pure-projection boundary // into an AGGREGATING terminal RETURN -- the case the clause-list fusion // cannot see, because the terminal projection is not a clause. Same // license as the clause fusion (plain 1:1 map, total substitution), same // fail-open posture. Returns the possibly-shortened clause list and the // projection to plan the terminal segment with; the caller's part is // never mutated (the adaptive sibling rebuild re-plans the same AST). // Iterates to a fixpoint: chained LETs stack as successive pure // boundaries, each of which folds in turn. func fuseTrailingProjectionIntoRet( []ast.Clause, ast.Projection) ([]ast.Clause, ast.Projection) { for { := len() if == 0 || !projectionIsAggregated(&) { return , } , := [-1].(*ast.With) if ! || .Where != nil { return , } , := pureProjectionSubst(&.Proj) if ! { return , } , := inlineProjection(&, nil, ) if ! { return , } , = [:-1], .Proj } } // fuseProjectionBeforeAggregate fuses a pure-projection boundary followed // by an aggregating boundary into the aggregate, so the streaming // aggregator folds matched rows without materializing the projected set. // Conservative: fires only when the projection is a plain 1:1 map and // every inlined reference is safely substitutable. Iterates to a // fixpoint so chained LET boundaries all fold, innermost first. func fuseProjectionBeforeAggregate( []ast.Clause) []ast.Clause { for { := fuseProjectionBeforeAggregateOnce() if len() == len() { return } = } } // fuseProjectionBeforeAggregateOnce is one left-to-right fusion sweep. func fuseProjectionBeforeAggregateOnce( []ast.Clause) []ast.Clause { := make([]ast.Clause, 0, len()) for := 0; < len(); ++ { , := [].(*ast.With) if && .Where == nil { if , := pureProjectionSubst(&.Proj); && +1 < len() { if , := [+1].(*ast.With); && projectionIsAggregated(&.Proj) { if , := inlineProjection(&.Proj, .Where, ); { = append(, ) ++ // consume the aggregating boundary we fused into continue } } } } = append(, []) } return }