Repository navigation
Description
ArcadeDB version
ArcadeDB 26.8.1-SNAPSHOT
Build:
1134185d5494f5ab0583da4a508d846449f8e04c/1785129272315/main
Environment
- Host OS: Linux x86_64
- Deployment: Docker (
arcadedata/arcadedb:latest) - Runtime: OpenJDK
- Query interface: HTTP command API
- Query language: Cypher
Description
A MATCH containing a relationship inline WHERE predicate returns different aggregate results depending only on whether the query uses count(*) or count(r).
For the same matched pattern:
count(*)returns0count(r)returns1- directly returning
r.tagproduces the expected matching row
Because r is bound by a regular MATCH and is non-null for every produced row, count(*) and count(r) should return the same value.
The failure specifically appears when count(*) is combined with property access on the relationship variable inside the inline predicate:
[r:E WHERE r.tag = "ok"]A literal inline predicate and the equivalent clause-level WHERE form both work correctly.
Related issues
This appears related to, but distinct from, several previous issues:
- ArcadeDB may ignore a relationship predicate written directly inside the relationship pattern. #3951/fix: inline relationship WHERE predicate is now applied #3953 concerned relationship inline
WHEREpredicates being ignored during regularMATCHevaluation. The current predicate is not simply ignored: if it were ignored, both relationships would be counted and the result would be2, not0. count(*)with inline-filtered start node and anonymous endpoint returns global relationship count #5071 concernedcount(*)returning the global relationship count for a pattern with an inline-filtered source node and an anonymous endpoint. The current result is0and requires a relationship inline predicate.- Cypher count(*) after OPTIONAL MATCH drops null rows #5094 concerned
count(*)dropping null-preserving rows afterOPTIONAL MATCH. The current reproduction uses a regularMATCHand contains no optional rows.
Steps to reproduce
Run each statement separately against a clean database.
1. Clean the database
MATCH (n)
DETACH DELETE n;2. Create the test graph
CREATE (a:A {v:1}), (b:A {v:2});
MATCH (a:A {v:1}), (b:A {v:2})
CREATE
(a)-[:E {tag: "ok"}]->(b),
(a)-[:E {tag: "bad"}]->(b);The graph contains two :E relationships:
tag = "ok"
tag = "bad"
Exactly one relationship satisfies r.tag = "ok".
3. Failing query
MATCH (a:A {v:1})-[r:E WHERE r.tag = "ok"]->(b:A)
RETURN count(*) AS c;Actual result:
c = 0
Expected result:
c = 1
4. Change only the aggregate expression
MATCH (a:A {v:1})-[r:E WHERE r.tag = "ok"]->(b:A)
RETURN count(r) AS c;Result:
c = 1
Expected behavior
The predicate:
r.tag = "ok"matches exactly one relationship and therefore produces exactly one row.
Both aggregate expressions should consequently return:
count(*) = 1
count(r) = 1
Actual behavior
count(*) = 0
count(r) = 1
Changing only the aggregate expression changes the result of the preceding MATCH.
Controls
Control 1: Direct row materialization
MATCH (a:A {v:1})-[r:E WHERE r.tag = "ok"]->(b:A)
RETURN r.tag AS tag;Result:
tag = "ok"
The relationship inline predicate produces the expected row when the relationship property is returned directly.
Control 2: Literal inline predicate
MATCH (a:A {v:1})-[r:E WHERE 1=1]->(b:A)
RETURN count(*) AS c;Result:
c = 2
This shows that count(*) can work with the relationship inline predicate syntax when the predicate does not access a relationship property.
Control 3: Clause-level WHERE
MATCH (a:A {v:1})-[r:E]->(b:A)
WHERE r.tag = "ok"
RETURN count(*) AS c;Result:
c = 1
Moving the same condition from the relationship pattern to a clause-level WHERE restores the correct result.
Workaround
Use a clause-level WHERE predicate:
MATCH (a:A {v:1})-[r:E]->(b:A)
WHERE r.tag = "ok"
RETURN count(*) AS c;Alternatively, use count(r) when the relationship variable is already bound:
MATCH (a:A {v:1})-[r:E WHERE r.tag = "ok"]->(b:A)
RETURN count(r) AS c;Cross-engine comparison
| Query shape | Neo4j 2026.06.0 | ArcadeDB 26.8.1-SNAPSHOT |
|---|---|---|
Inline r.tag = "ok" with count(*) |
1 |
0 |
Inline r.tag = "ok" with count(r) |
1 |
1 |
Inline r.tag = "ok" returning r.tag |
1 row | 1 row |
Inline 1=1 with count(*) |
2 |
2 |
Clause-level WHERE r.tag = "ok" with count(*) |
1 |
1 |
Isolated recheck
Reproduced in a fresh arcadedata/arcadedb:latest Docker container with a clean database.
The failing query was executed three times and returned 0 in all three runs. All controls passed in all three runs.
Why this looks like a bug
-
Internal aggregate contradiction
The same
MATCHproduces one materialized row andcount(r) = 1, butcount(*) = 0. -
count(*)andcount(r)must agree hereThe relationship variable is bound by a regular
MATCHand is therefore non-null in every produced row. Both expressions should count the same rows. -
Predicate-location control
Moving the identical condition to a clause-level
WHERErestores the correctcount(*)result. -
Literal-versus-property control
A literal relationship inline predicate works, while an inline predicate that accesses
r.tagfails only on thecount(*)path. -
Silent wrong result
The query completes successfully without an error or warning but returns an incorrect aggregate value.
Impact
Queries that combine count(*) with a relationship inline WHERE predicate that accesses a relationship property can silently return an incorrect count.
The equivalent query using a clause-level WHERE or count(r) returns the correct value.
Activity
fix(#5463, #5462): pin count(*) against a relationship inline WHERE p…
fix(#5463, #5462): pin count(*) against a relationship inline WHERE p…