// MATCH-scope relationship-uniqueness marking (port of the Rust// recognize.rs::mark_rel_uniqueness): within one MATCH clause (= one// scope, spanning its comma patterns and any planner splits) every// relationship must be pairwise distinct -- ISO GQL's DIFFERENT EDGES// default match mode / openCypher's relationship isomorphism.
package plan// markRelUniqueness marks each rel-binding op's uniqueness participation.// Tracking is gated on relationship-TYPE intersection: two ops whose type// sets cannot name the same relationship (disjoint, non-empty) never// conflict, so a typical multi-hop clause over distinct types stays// completely untracked and zero-cost. An op with an intersecting op// EARLIER in execution order gets Check (its candidate must not reuse a// used pair); one with an intersecting op LATER gets Contribute (it// pushes its pair(s)). A contributing var-length loses DedupEndpoints// (trails with different rel sets must stay distinct rows for the// downstream exclusion to be exact).func markRelUniqueness( []Stage) {typestruct {uint32 []string , int }var []for , := range { , := .(*MatchStage)if ! || .Walk {// REPEATABLE ELEMENTS: walk semantics, no uniqueness pairs.continue }for := range .Ops { := &.Ops[]if .Kind == OpExpand || .Kind == OpVarExpand { = append(, {: .Scope, : .Types, : , : }) } } }for := range { := &[] , := false, falsefor := range [:] {if []. == . && intersects(., [].) { = truebreak } }for := + 1; < len(); ++ {if []. == . && intersects(., [].) { = truebreak } }if ! && ! {continue } := [.].(*MatchStage) := &.Ops[.] .Uniq = &RelUniq{Scope: ., Check: , Contribute: }if .Kind == OpVarExpand && { .DedupEndpoints = false } }}// intersects reports whether two type lists can name the same relationship.// An empty type list matches any relationship, so it intersects everything.func intersects(, []string) bool {iflen() == 0 || len() == 0 {returntrue }for , := range {for , := range {if == {returntrue } } }returnfalse}// remarkRelUniqueness recomputes every tracked op's Check/Contribute over// the FINAL stage list's EFFECTIVE execution order: hash-join extraction// moves the consumed connecting expand (the probe) and the collected build// ops relative to the ops left in place, so flags assigned on the nested// order can invert -- an op that was the last of its scope (Check-only)// can come to execute FIRST as the join's probe, pushing nothing while the// op now after it contributes to nobody, and a reused relationship sails// through. Extraction never changes WHICH ops intersect (only their// order), so the tracked set is exactly the ops already carrying Uniq;// their recorded scope survives the move. Effective order is stage order// with a hash join expanding to its build stages' ops then its probe// (builds materialize before any probe emission).func remarkRelUniqueness( []Stage) {typestruct {uint32 []string *BindOp }var [] := func( *MatchStage) {if .Walk {return }for := range .Ops {if := &.Ops[]; .Uniq != nil { = append(, {: .Uniq.Scope, : .Types, : }) } } }for , := range {switch s := .(type) {case *MatchStage: ()case *HashJoinStage:for , := range .Build { () }if .Probe.Uniq != nil { = append(, {: .Probe.Uniq.Scope, : .Probe.Types, : &.Probe}) } } }for := range { := &[] , := false, falsefor := range [:] {if []. == . && intersects(., [].) { = truebreak } }for := + 1; < len(); ++ {if []. == . && intersects(., [].) { = truebreak } } ..Uniq = &RelUniq{Scope: ., Check: , Contribute: }if ..Kind == OpVarExpand && { ..DedupEndpoints = false } }}
The pages are generated with Goldsv0.8.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.