Skip to content

Single-node labeled pattern (a:Label) does not filter by label (vertex-only EXISTS skips label quals) #2443

Description

@gregfelice

Summary

Single-node labeled pattern expressions (a:Label) are accepted as boolean expressions but do not filter by label — they evaluate as trivially true. This is a pre-existing limitation in the vertex-only pattern transform, surfaced by #2360 (which lets a bare pattern appear anywhere an expression is valid).

Reproduction

SELECT * FROM cypher('g', $$ CREATE (:Person {name:'Alice'}), (:Animal {name:'Rex'}) $$) AS (r agtype);

-- expected: only "Alice"; actual: "Alice" AND "Rex"
SELECT * FROM cypher('g', $$ MATCH (a) WHERE (a:Person) RETURN a.name $$) AS (n agtype);

-- expected: a boolean reflecting whether a has label Person; actual: always true
SELECT * FROM cypher('g', $$ MATCH (a:Person) RETURN (a:Person) $$) AS (b agtype);

Root cause

make_path_join_quals() in src/backend/parser/cypher_clause.c:5454 early-returns for vertex-only patterns:

/* for vertex only queries, there is no work to do */
if (list_length(entities) < 3)
{
    return NIL;
}

The label-filter quals (_extract_label_id(id) = label_id) are only emitted inside make_join_condition_for_edge(), which is never reached without a relationship. So a single-vertex pattern desugars to an EXISTS subquery with no label constraint → trivially true.

Scope

Suggested fix

Emit the label-filter qual for single bound vertices before the early return in make_path_join_quals (or hoist the label-filter logic out of make_join_condition_for_edge so it applies to vertex-only patterns), plus a regression test asserting WHERE (a:Person) filters and RETURN (a:Label) reflects the label.

Found during review of #2360.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions