// 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.
package exec import ( ) // uniqKey is one used relationship: its canonical endpoint pair, tagged by // uniqueness scope. dead marks a capture-only entry (see uniqEnv.capture): // it is recorded for a later probe-time check but is NOT a live used pair, // so used() ignores it. check carries the pushing op's original Check flag // for the probe's replay classification. type uniqKey struct { scope uint32 a, b graph.NodeID dead bool check bool } // uniqEnv is the used-pair stack one in-flight row carries. capture is the // hash-join build mode: an op whose original marking is Check-only (its // collisions were against pairs bound OUTSIDE this isolated env) pushes a // dead entry so the probe can replay that check against the outer env -- // the build stack then holds exactly the pairs the original nested order // would have, minus the outer branch's, keeping build-internal Check // semantics exact. type uniqEnv struct { stack []uniqKey capture bool } // used reports whether the scope already bound the pair (live entries // only; capture-mode dead entries are bookkeeping, not used pairs). func ( *uniqEnv) ( uint32, , graph.NodeID) bool { for , := range .stack { if !.dead && .scope == && .a == && .b == { return true } } return false } // uniqPair is the edge-canonical relationship-uniqueness key for a hop // from `from` to `to` over dir: the ORDERED pair in the relationship's own // source->target orientation ((from, to) for an outgoing hop, (to, from) // for an incoming one), or the UNORDERED pair for an undirected hop. // // - A directed hop keys on the edge's (source, target), so a // there-and-back cycle's two distinct edges a->b and b->a get distinct // keys and both may be used in one clause -- while the SAME physical // edge traversed from either endpoint (outgoing a->b vs incoming b<-a) // normalizes to one key and is never used twice. // - An undirected hop keys on the unordered pair, so the double-stored // undirected convention (a->b + b->a for one logical edge) collapses // to one edge. Genuine parallel rels between one pair also collapse -- // the documented multigraph deviation, matching the trail walk's key. func uniqPair( graph.Direction, , graph.NodeID) (graph.NodeID, graph.NodeID) { switch { case graph.Outgoing: return , case graph.Incoming: return , } return min(, ), max(, ) }