// Prepared: a parsed, auto-parameterized, and planned query, ready to // execute repeatedly without re-incurring parse/plan cost -- the unit the // plan cache holds, exposed directly for callers managing their own reuse.
package gql import ( chickpeas ) // Prepared is a compiled query. The plan is auto-parameterized (its // inline constants are lifted and stored), so it is value-independent by // construction; its cost-based choices reflect the statistics of the // snapshot it was prepared against -- executing against another snapshot // is legal and correct, possibly suboptimal. An EXPLAIN/PROFILE query // prepares too: Execute then returns the rendered plan. type Prepared struct { plan *plan.Plan mode ast.QueryMode lifted []value.Value planTime time.Duration } // Prepare parses, desugars, auto-parameterizes, and plans query once // against g's statistics. func ( *chickpeas.Snapshot, string) (*Prepared, error) { := time.Now() , := parseDesugar() if != nil { return nil, } := semantics.AutoParameterize() , := plan.Build(, graph.New()) if != nil { return nil, wrapStage() } return &Prepared{plan: , mode: .Mode, lifted: , planTime: time.Since()}, nil } // Execute runs the prepared plan against g with explicit $name parameter // values (an unsupplied parameter reads as null); the stored lifted // constants rebind automatically. For an EXPLAIN/PROFILE query this // returns the rendered plan instead. The adaptive anchor choice runs here // exactly as on the cached path: a statement prepared once and executed // many times with different parameter values is the canonical // parameter-sniffing shape, so the value-resolved sibling choice matters // MOST on this path. func ( *Prepared) ( *chickpeas.Snapshot, map[string]value.Value) (*Rows, error) { := graph.New() := &eval.Ctx{G: , Params: .lifted, Named: , ForceInterp: forceInterp} return execPlan(, chooseAdaptivePlan(.plan, , ), .mode, .planTime, ) } // Columns is the output column names the plan produces, in order. func ( *Prepared) () []string { return .plan.Columns }