Skip to content

Closed VLP with lower bound 0 ((a)-[*0..N]-(a)): edge-uniqueness needed to count cycles (currently fails loud) #628

Description

@genezhang

Follow-up to #625.

#625 fixed closed VLP patterns (same variable both endpoints) for lower bound >= 1 by emitting t.start_id = t.end_id on the recursive-CTE outer query. The *0..N case is currently made to fail loud (UnsupportedFeature) rather than return a silent undercount.

Why loud, not fixed: a *0..N recursive CTE enforces NODE-uniqueness (NOT has(vp.path_nodes, end_id)) — the zero-hop base case has no edges to seed path_edges, so it cannot use edge-uniqueness (documented in variable_length_cte.rs, #598 part 2). Node-uniqueness forbids a walk from ever revisiting any node including its start, so no hop>0 row can satisfy start_id = end_id. Adding the cycle constraint therefore matched ONLY the zero-length self rows: (a)-[:FOLLOWS*0..2]->(a) returned 8 where the true cycle count is 14 (8 zero-length self + 6 real 2-cycles); undirected returned 8 vs true 20.

Repro (social benchmark, currently errors):

MATCH (a:User)-[:FOLLOWS*0..2]->(a) RETURN count(*)   -- want 14
MATCH (a:User)-[:FOLLOWS*0..2]-(a)  RETURN count(*)   -- want 20

Fix needed: when a closed pattern (left_connection == right_connection) has lower bound 0, route the recursive arm to EDGE-uniqueness (path_edges) instead of node-uniqueness, so real cycles survive. The zero-hop base has empty path_edges (CAST([] AS Array(...))), and hops>=1 seed normally — need to confirm this doesn't hit the base/recursive column-mismatch the #598 note warns about (which was about seeding path_edges only in the base). Result should be: all zero-length self rows (start=end trivially) UNION real cycles (hop>=1 returning to start, edge-unique).

Workaround today: use lower bound >= 1 (*1..N) to count cycles.

shortestPath *0.. self is correctly handled (exempt from the guard) — node-uniqueness is right there and the zero-length path is the shortest self-path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions