Summary
A WHERE clause combining <bool> = true OR EXISTS { … } with a grouped AND NOT (EXISTS { … } OR EXISTS { … }) returns 0 rows when both outer entities are bound by separate MATCH statements
(cross-product) — even when the boolean branch alone matches. The same logic works correctly when the second entity is matched inside an outer EXISTS { MATCH … }.
Possibly related to but distinct from #4097 (which addressed EXISTS { RETURN n } over outer-variable expressions, fixed in 26.5.1).
Environment
- ArcadeDB 26.5.1-SNAPSHOT (build
1dc68da159f12ef9c8c436e5b5998a7ab483714b)
- HTTP API
/api/v1/command/<db> with language=cypher
- Reproduced fresh — no application-side wrappers
Reproduction
Schema + data:
CREATE VERTEX TYPE Owner;
CREATE PROPERTY Owner.id STRING;
CREATE VERTEX TYPE Item;
CREATE PROPERTY Item.id STRING;
CREATE PROPERTY Item.flag BOOLEAN;
CREATE EDGE TYPE rel;
CREATE EDGE TYPE excl;
CREATE (:Owner {id: "u"});
CREATE (:Item {id: "c", flag: true});
(No edges of any kind.)
Probe B1 — control: 2-MATCH + boolean only ✓
MATCH (u:Owner {id: "u"})
MATCH (c:Item)
WHERE c.flag = true
RETURN c.id AS id
Returns [{"id":"c"}] ✓
Probe B2 — 2-MATCH + bool OR EXISTS{…} ✓
MATCH (u:Owner {id: "u"})
MATCH (c:Item)
WHERE c.flag = true
OR EXISTS { MATCH (u)-[:rel]->(c) }
RETURN c.id AS id
Returns [{"id":"c"}] ✓ — boolean branch matches.
Probe B3 — adding AND NOT EXISTS { … } ❌
MATCH (u:Owner {id: "u"})
WHERE (c.flag = true OR EXISTS { MATCH (u)-[:rel]->(c) })
AND NOT EXISTS { MATCH (u)-[:excl]->(c) }
RETURN c.id AS id
Returns [] — expected 1 row (no excl edge means NOT EXISTS is true).
Probe B4 — full grouped exclusion ❌
MATCH (u:Owner {id: "u"})
MATCH (c:Item)
WHERE (c.flag = true OR EXISTS { MATCH (u)-[:rel]->(c) })
AND NOT (
EXISTS { MATCH (u)-[:excl]->(c) }
OR EXISTS { MATCH (u)-[:excl*1..3]->(c) }
)
RETURN c.id AS id
Returns [] — expected 1 row.
Probe B5 — control: same WHERE wrapped under single outer MATCH ❌
MATCH (c:Item)
WHERE EXISTS {
MATCH (u:Owner {id: "u"})
WHERE (c.flag = true OR EXISTS { MATCH (u)-[:rel]->(c) })
AND NOT (
EXISTS { MATCH (u)-[:excl]->(c) }
OR EXISTS { MATCH (u)-[:excl*1..3]->(c) }
)
}
RETURN c.id AS id
Also returns [] — same bug surfaces when the same WHERE shape is nested.
Expected behavior
All four probes B2-B5 should return [{"id":"c"}] because:
- The boolean branch (
c.flag = true) matches — inclusion is satisfied.
- There are no
:excl edges from the owner — exclusion is empty.
- Therefore
(inclusion) AND NOT (exclusion) should be true.
Impact
This blocks a single-query implementation of any include/exclude resolver where multiple inclusion vectors (boolean class flag + EXISTS over edges) must combine with multiple exclusion vectors. The current
workaround is two separate UNION queries + application-side dedup (one inclusion query per branch + one exclusion query, with subtraction in the consumer), roughly 110 lines of extra code per resolver.
Possibly related to #4097 (fixed 2026-05-06, addressed EXISTS { RETURN n } shapes). The current case appears separate — inclusion EXISTS works (probe B2 ✓), exclusion-only NOT EXISTS works in isolation,
but the combination collapses every row.
Summary
A WHERE clause combining
<bool> = true OR EXISTS { … }with a groupedAND NOT (EXISTS { … } OR EXISTS { … })returns 0 rows when both outer entities are bound by separateMATCHstatements(cross-product) — even when the boolean branch alone matches. The same logic works correctly when the second entity is matched inside an outer
EXISTS { MATCH … }.Possibly related to but distinct from #4097 (which addressed
EXISTS { RETURN n }over outer-variable expressions, fixed in 26.5.1).Environment
1dc68da159f12ef9c8c436e5b5998a7ab483714b)/api/v1/command/<db>withlanguage=cypherReproduction
Schema + data:
(No edges of any kind.)
Probe B1 — control: 2-MATCH + boolean only ✓
Returns
[{"id":"c"}]✓Probe B2 — 2-MATCH +
bool OR EXISTS{…}✓Returns
[{"id":"c"}]✓ — boolean branch matches.Probe B3 — adding
AND NOT EXISTS { … }❌Returns
[]— expected 1 row (noexcledge means NOT EXISTS is true).Probe B4 — full grouped exclusion ❌
Returns
[]— expected 1 row.Probe B5 — control: same WHERE wrapped under single outer MATCH ❌
Also returns
[]— same bug surfaces when the same WHERE shape is nested.Expected behavior
All four probes B2-B5 should return
[{"id":"c"}]because:c.flag = true) matches — inclusion is satisfied.:excledges from the owner — exclusion is empty.(inclusion) AND NOT (exclusion)should be true.Impact
This blocks a single-query implementation of any include/exclude resolver where multiple inclusion vectors (boolean class flag + EXISTS over edges) must combine with multiple exclusion vectors. The current
workaround is two separate UNION queries + application-side dedup (one inclusion query per branch + one exclusion query, with subtraction in the consumer), roughly 110 lines of extra code per resolver.
Possibly related to #4097 (fixed 2026-05-06, addressed
EXISTS { RETURN n }shapes). The current case appears separate — inclusion EXISTS works (probe B2 ✓), exclusion-only NOT EXISTS works in isolation,but the combination collapses every row.