Repository navigation
Direct Cypher row lowering rejects scalar multi-alias projections from a single MATCH #981
Description
Activity
- added 5 commits that reference this issue
on Mar 31, 2026 Additional measured benchmark manifestation from
pyg-benchon March 31, 2026:interactive-complex-8/Q8. Recent repliesno longer hard-fails, but direct Cypher row lowering still misbinds projected aliases.Observed shape:
MATCH (start:Person {id: $personId})<-[:HAS_CREATOR]-(:Message)<-[:REPLY_OF]-(comment:Comment)-[:HAS_CREATOR]->(person:Person) RETURN person.id AS personId, person.firstName AS personFirstName, person.lastName AS personLastName, comment.creationDate AS commentCreationDate, comment.id AS commentId, comment.content AS commentContent ORDER BY commentCreationDate DESC, commentId ASC LIMIT 20
Actual mismatch pattern on current
master/v0.53.10(7095102df492feed0ce7a83240ee406c779c5f81):personIdis populated withcommentIdpersonFirstName/personLastNamecome back asNone
So
#981is still the right umbrella for measured multi-binding projection problems, but the current failure mode is sometimes silent semantic corruption, not only a validation/planner rejection.New measured SNB benchmark manifestations from
pyg-benchagainst explicitmastersnapshot7095102df:interactive-complex-4/ new-topics: direct Cypher fails before execution with[unsupported-cypher-query] Cypher row lowering currently supports one MATCH source alias at a time | field: return | value: ['post', 'tag']. GFQL workaround matches the staged fixture via friend traversal + local post-tag aggregation.\n-interactive-complex-11/ job-referral: direct Cypher fails before execution with[unsupported-cypher-query] Cypher row lowering currently supports one MATCH source alias at a time | field: where | value: 'not(person=friend)'. GFQL workaround matches the staged fixture via 1..2-hop friend expansion + local employment/company join.\n\nCurrent measured SNB floor is now12/29official queries, and#981remains the largest Cypher unlock by affected-query count.
Benchmark follow-up from
pyg-benchafter rerunning against isolated ambientgraphistry v0.53.11:Artifact:
results/runs/local-snb-interactive-v05311-rerun/
interactive-complex-9/recent-network-messagesnow gets past the earlier#1000WITH collect(distinct friend) -> UNWIND -> MATCHblocker and lands here instead.Current residual message:
[unsupported-cypher-query] Cypher row lowering currently supports one MATCH source alias at a time | field: where | value: 'NOT friend = root'
So for benchmarks,
Q9has moved from the#1000bucket into the broader multi-binding row-lowering family tracked here.Fresh follow-on investigation from #1005 / #1006 adds another concrete acceptance case for this issue family.
New exact direct repro on current master:
MATCH (:A {id: $seed})-[:R]->(b:B) WITH b, b.id AS bid MATCH (b)-[:S]->(c:C), (c)-[:T]->(d:D) RETURN bid, d.id AS did- current error:
Cypher MATCH after WITH currently supports a single trailing MATCH pattern
Important finding: when that guard is relaxed experimentally, the query does not become correct. Instead it exposes the older multi-alias bindings/projection corruption underneath. Plain non-reentry controls on the same connected multi-pattern path are already wrong too, e.g.:
MATCH (b:B)-[:S]->(c:C), (c)-[:T]->(d:D) RETURN c.id AS cid, d.id AS did- observed corrupted rows where
cid/didcollapse onto the wrong aliases
The immediate culprit is the existing
rows(alias_endpoints=...)shortcut, which only knowssrc/dstand cannot represent distinct aliases across a longer connected path. That makes #1006 look like another symptom of the broader bindings-table / multi-alias row-projection gap already described here and in #880.So #1006 should likely be treated as an acceptance case / benchmark-facing symptom under #981 rather than a separate narrow implementation lane.
Draft implementation is up in #1008. This lane now has the connected multi-alias row-binding path, local broad validation, and targeted DGX cudf proof for the admitted slice.
Benchmark clarification from the latest current-master
dgx-sparksweep on14dafaf6b951954d8de840f9236f3e874249ebac:\n\n-interactive-complex-8/recent-repliesno longer belongs in the#981bucket on current master. Direct Cypher now returns the expected staged-fixture rows.\n - artifact:results/runs/dgx-spark-snb-interactive-ic8-origin-master-14dafaf6b9-fresh-r1/\n- the current-master benchmark lanes still reproducing#981are:\n -interactive-complex-2/recent-friend-messages\n -interactive-complex-4/new-topics\n -interactive-complex-9/recent-network-messages\n -interactive-complex-11/job-referral\n\nSo#981is still live for benchmark coverage, but the oldrecent-repliesexample is now stale on current master.
Summary
Direct Cypher currently rejects scalar projections that need values from more than one alias in the matched pattern, even when the final projection only returns scalars.
This showed up immediately while trying to map the first
LDBC SNB Interactivereads intopyg-bench.Environment used for repro:
graphistry/pygraphistryebe7d0ae827d724a8779e123c3965ec723581015uv run python ...Minimal repro
Observed behavior
Both queries fail with:
Expected behavior
These should return a single row with both scalar values:
[{'a_id': 'a', 'b_id': 'b'}]Why this matters
This blocks straightforward scalarized projections for official benchmark queries, for example:
SNB IS1: person fields plusp.id AS cityIdSNB IS3: friend fields plusr.creationDate AS friendshipCreationDateLikely relation
This may share an underlying fix with
#880, but this is the narrower direct-Cypher user-visible failure mode that is easy to reproduce.