package exec

Import Path
	github.com/freeeve/gochickpeas/gql/internal/exec (on go.dev)

Dependency Relation
	imports 17 packages, and imported by one package

Involved Source Files The group-by aggregator: rows route to their group's accumulators (implicit group-by-the-non-aggregate-keys), then one output row per group finalizes with ordering/pagination. count/sum/avg/min/max/collect with per-aggregate DISTINCT; nested-aggregate scalar wrappers read hidden accumulator slots and truncate them after. Encounter order of groups is preserved (observable in unordered results). Aggregation execution: routing each matched row into its group's accumulators (update), assembling one output row per group with the nested-aggregate wrappers, ordering, and pagination (finalize), the aggregated terminal sink, and percentile finalization. Split from aggregate.go, which holds the aggregator state and group-key packing. CALL procedure kernels: dispatch to the engine's analytics and index kernels through the Native capability (the per-row crossing sink lives in stream.go). Per-node procedures cross each input row with one row per node id (NodeSlot = the node, ValueSlot = its scalar); the index-backed search procedures yield one row per hit node in ascending id order. Fused columnar aggregation: a chain marked by plan/colagg.go -- one bare label-scan segment, a run of stage-less LET boundaries, and a stage-less aggregated boundary -- runs as ONE typed pass over the scanned label's ids. Filters run through the per-candidate predicate machinery, group keys and aggregate arguments through typed column reads resolved across the boundary chain by name; grouping, aggregate state, post-aggregation wrappers, ordering, and pagination reuse the general path's exact kernels (aggState, sortRowsByOrder, paginate), so the fused result is identical by construction. ANY expression the classifier cannot express over typed columns declines the whole chain back to the general pipeline. Classification is shape-generic: it never asks what query a chain came from, only whether its expressions fit the typed vocabulary. The columnar-aggregate chain environment: resolving each per-row boundary projection against the scanned candidate, classifying an expression into a typed per-candidate key function (property read, temporal component, label test, searched CASE), and the range-window optimization that narrows the scan to an indexed key's window. Split from colagg.go, which holds the fusion driver (tryColumnarAggChain). Date-truncation range rewrite: a WHERE conjunct of the shape date(<var>.<key>) = <constant Date> tests day membership, which over an epoch-millis integer column is exactly the half-open range [day, day + 24h) on the RAW value. Rewriting the conjunct to two property-vs-constant comparisons lets the pushdown machinery place and batch-sweep them like any other integer filter, instead of evaluating a temporal constructor per row -- the dominant filter shape in date-heavy analytic queries. The rewrite fires on generic structure (a resolved date() call over an integer-or-absent column against a constant Date), never on query identity. Package exec runs a compiled Plan against the graph seam. This file is the RowEval seam: every filter/projection evaluates through it, so the executor never cares whether the interpreted or the columnar compiled form is behind a given expression. Execute: run a plan's UNION branches and combine their rows (port of the Rust exec.rs entry points, minus the recognizer kernel dispatch). Fixed-hop expansion: one relationship step from a bound node, plus the bound-target rebind semijoin (probe a memoized reverse-neighbor set instead of re-expanding per row). Group-join stage runner: the decorrelated OPTIONAL-MATCH aggregate join. The standalone inner plan runs once (lazily, on the first outer row) into a key -> aggregate-values table; each outer row binds its synthetic aggregate slots by correlation-key lookup, with the aggregates' empty-group identities as the fill. The segment projection re-aggregates the synthetic columns, so the emitted rows reproduce the nested left-join answer exactly. Hash-join stage runner: build the independent branch once per distinct external-slot tuple (an isolated capture-mode uniqueness env records each row's relationship pairs), then per outer row expand the probe hop and emit the key-matching payload rows -- replaying each payload's captured Check pairs against the outer used-pair env and pushing its live pairs for downstream ops, so the emitted multiset is exactly what the original nested execution produced. int128.go The bind-chain walker: iterative DFS over a MATCH stage's ops, binding each level's candidates into the row and pruning with the pushed-down conjuncts (port of the Rust gen_matches). M15 executes scan ops; expansion ops land in M17 and are rejected at plan validation. Cross-boundary fusion for [aggregating boundary] -> [identity ORDER BY boundary] -> [DISTINCT column-subset + LIMIT]: DISTINCT keeps each distinct tuple's FIRST row under the sort's total order and LIMIT keeps the leading bound, so each tuple's effective position is the MINIMUM of its rows' key vectors (argmin) and the result is a bounded selection over those minima. Streaming the aggregate's finalized groups through a per-tuple argmin map replaces the full group-row materialization, the full-width sort decoration, and the sort itself. Named-path assembly (MATCH p = ...): after the pattern binds, each row's path value is reconstructed from its start node and the hop's bound relationship position(s); the matchSink then runs the stage WHERE as a post-path filter so predicates over nodes(p)/rels(p)/length(p) resolve. Non-aggregated projection: the terminal sink evaluates the output columns per pushed row, applies DISTINCT on arrival (before ORDER BY/LIMIT, as the standard requires -- first occurrence kept), then finalize sorts and paginates. Projected rows live in a chunked arena; the matched row is retained (arena-copied) only when an ORDER BY key is not a projected column. The Rust bounded top-k heap remains a possible follow-up with byte-identical results. ORDER BY and pagination for materialized projection rows: a decorate-sort-undecorate that evaluates each row's key vector once, with a typed fast path (numeric/entity key columns pack into order-preserving words so the comparator is pure word compares) and a bounded top-k selection under LIMIT. Split from project.go, which holds the streaming projection sink. Sub-plan execution for CALL { } subqueries (the per-row lateral-join sinks live in stream.go). Row-independent scan candidate sources: label/property/text-match/ id-seek/all-nodes (port of the Rust fresh_scan family). Segment runner: build the segment's sink chain (stages in order, then the terminal projection/aggregation sink), push each seeded input row through it, finalize, and apply the boundary's WHERE. This is the streaming form of the Rust M18 fast paths -- results are identical to the former stage-by-stage materialization (pure allocation optimization). Semijoin reduction for constant-anchored chains (task 205 round 8): a run of anonymous expand hops that leads from a pattern variable into a node that is CONSTANT across the stage's input rows is a fixed unary predicate on that variable -- (c)-[:LOC]->(:City)-[:PART]->(country) with country identical on every seeded row tests nothing but c. The chain's ops are absorbed: the qualifying node set is enumerated ONCE by walking the chain backwards from the constant, and the variable's binding level sweeps candidates against it at fill time, so the per-row hop enumeration (and its row traffic) disappears. Fires on generic structure -- an into-bound tail whose target the existing batch-constant analysis proves invariant -- never on query identity. Path-search stages (ANY SHORTEST / ALL SHORTEST): minimum-hop BFS with parent links, a single-source tree memo for sources shared by many rows, and the all-shortest backward enumeration over the distance map. Every form runs on the one spWalk frontier core, so the hop-filter and depth-bound semantics live in a single place. The weighted form is the COST clause: MATCH p = ANY SHORTEST <pattern> COST <expr>. All-shortest-paths enumeration: a reusable single-source minimum-hop parent tree (spTree) for hop-minimal single paths, plus the forward-BFS + backward-DFS that enumerates every distinct minimum-hop path a..b and resolves each path's relationship positions. Split from shortest.go, which holds the stage runner, scratch, and single-path search. MATCH stage runner: compile the stage's matchers and WHERE-conjunct pushdown buckets once, then walk each input row through the bind chain. The push pipeline: a segment's stages run as a chain of row sinks, each holding one reused full-width row buffer, so matched rows flow through the chain without per-row allocation. Only the terminal sink retains rows (in chunked arenas); the shortest-path stage keeps its batch semantics behind a buffering barrier. Depth-first push order equals the former materialize-then-iterate order, so group encounter order, DISTINCT first-occurrence, and stable-sort ties are unchanged. MATCH-scope used-relationship state (port of the Rust exec.rs UniqEnv): one in-flight row's bound relationship-uniqueness keys, tagged by scope (= source MATCH clause). Owned by the segment chain and threaded through genMatches and its sinks so a scope spanning chained stages (comma patterns, planner splits) sees one stack per row; the DFS's push/pop discipline empties it between rows automatically. Tiny in practice (<= the number of tracked rel ops on the current partial row), so a linear slice beats hashing. Quantified (variable-length) expansion: bounded enumeration walks relationship-unique trails (one row per path, GQL TRAIL semantics); zero-length or unbounded quantifiers resolve the distinct reachable set via a dedup'd BFS so a cyclic walk terminates. Each walk mode threads the same hopGate seam: a stateless per-hop predicate and a stateful carry+accept constraint prune during the walk. Bounded trail enumeration: the depth-first walk that emits one endpoint per qualifying trail of length min..=max, enforcing relationship uniqueness (and ACYCLIC node uniqueness), carried-state pruning, and optional per-trail rel/pair collection. Split from varexpand.go, which holds the candidate generation and reachability (BFS) paths. The weighted shortest-path form of an SpStage (the ANY SHORTEST ... COST clause): a Dijkstra over (cost, hops, node) states keyed on (node, hops) -- the hop cap makes cost non-monotonic per node -- with the path reconstructed from parent links so relationships(p) scores the exact path the search optimized.
Package-Level Type Names (only one)
/* sort by: | */
RowEval is a bound expression in per-row-evaluable form. ( RowEval) Eval(ctx *eval.Ctx, row []value.Value, slots map[string]int) value.Value *github.com/freeeve/gochickpeas/gql/internal/compile.Compiled
Package-Level Functions (total 3)
Execute runs a plan and returns its rows in output-column order. Every plan construct the planner produces is executable as of M19, so execution is infallible once a plan builds.
ExecuteProfiled runs the plan while recording how many rows each operator produces. Segment profiles are pushed branch-major, segment-minor -- the order the explain renderer walks. PROFILE reports operator cardinalities, not the result set; each branch's final rows are discarded (the union combine is not a profiled operator).
InterpPinned exposes the counter to the harness's liveness assertion.