gregfelice opened a new pull request, #2444:
URL: https://github.com/apache/age/pull/2444

   ## Problem
   
   A single-node labeled pattern used as a boolean expression — e.g. `WHERE 
(a:Person)` or `WHERE EXISTS((a:Person))` — is accepted but does **not** test 
the bound vertex's label. It evaluates as trivially true, so the predicate 
matches every row.
   
   Repro (on `master`):
   
   ```sql
   SELECT * FROM cypher('g', $$ CREATE (:Person {name:'Alice'}), (:Animal 
{name:'Rex'}) $$) AS (r agtype);
   
   -- returns BOTH Alice and Rex; should return only Alice
   SELECT * FROM cypher('g', $$ MATCH (a) WHERE (a:Person) RETURN a.name $$) AS 
(n agtype);
   ```
   
   ## Root cause
   
   A single-node pattern expression desugars to an `EXISTS` sub-pattern. 
`make_path_join_quals()` returns early for vertex-only patterns 
(`list_length(entities) < 3`), emitting no quals. With no edge to carry a 
correlation, the sub-pattern references nothing from the enclosing query, so 
the planner produces an **uncorrelated one-time InitPlan** that is true 
whenever any vertex of that label exists — independent of the outer row.
   
   Relationship patterns are unaffected: the edge-driven join (`start_id = 
a.id`) correlates them to the outer variable, which is why `WHERE 
(a)-[:R]->(b)` works correctly.
   
   `EXPLAIN` before the fix — uncorrelated `InitPlan` with a `One-Time Filter`:
   
   ```
   InitPlan 1
     ->  Result
   One-Time Filter: ((InitPlan 1).col1)::agtype
   ```
   
   After the fix — correlated `SubPlan` referencing the outer `a_1`:
   
   ```
   SubPlan 1
     ->  Result
           One-Time Filter: ((_extract_label_id(a_1.id))::integer = 3)
   ```
   
   ## Fix
   
   In `make_path_join_quals()`, for a vertex-only pattern whose vertex carries 
a non-default label **and** whose variable is declared in an ancestor parse 
state (a correlated reference), emit an explicit label-id filter. `make_qual()` 
builds a name-based id reference that resolves to the outer variable, so the 
filter both **correlates** the sub-pattern to that variable and **enforces** 
the label.
   
   Freshly scanned, non-correlated vertices (no ancestor binding) are 
untouched, so `MATCH (a:Person)` and "does any X exist" `EXISTS` checks behave 
exactly as before.
   
   ## Testing
   
   Added regression coverage to `pattern_expression` against a graph containing 
a non-`Person` vertex:
   
   - `WHERE (a:Person)` → only the `:Person` vertices
   - `WHERE NOT (a:Person)` → only the non-`Person` vertex
   - `WHERE EXISTS((a:Company))` → only the `:Company` vertex
   
   All 41 regression tests pass (`make installcheck`).
   
   ## Note
   
   `RETURN (a:Label)` in a **projection** on an unlabeled bound variable still 
errors with "multiple labels for variable" — that is a separate, pre-existing 
guard, orthogonal to this fix, and is intentionally left unchanged.
   
   Fixes #2443
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to