support openCypher-like relationsiop-type edge alternation#2468
support openCypher-like relationsiop-type edge alternation#2468eeshwarg wants to merge 2 commits into
Conversation
Apache AGE's MATCH grammar rejects openCypher's relationship-type alternation syntax -
`MATCH ()-[:A|B]->()` fails at parse time with `syntax error at or near "|"`. For example,
a query like `SELECT * FROM cypher('kg_s7', $$ MATCH (p)-[:WORKS_AT|REPORTS_TO]->(c) RETURN c $$) AS (c agtype);`
throws a syntax error. A workaround for this today is to run something like
`SELECT * FROM cypher('kg_s7', $$ MATCH (p)-[r]->(c) WHERE type(r) IN ['WORKS_AT','REPORTS_TO'] RETURN c $$) AS (c agtype);`.
This change enables support for relationship-type alternation in accordance with the openCypher
standard. Changes are made in the grammar, AST and during transformation from the AST to Postgres
`Query` struct by adding the types to the `quals` list.
Variable-length relationship patterns with alternation `([:A|B*1..2])` are explicitly rejected
with `ERRCODE_FEATURE_NOT_SUPPORTED`.
Testing:
- Added regress test with cases with directed/undirected edges, and variable length edges
Future work:
- openCypher also support node-type alternation (like n:Person|Customer), which could be
added to AGE in a future PR
There was a problem hiding this comment.
Pull request overview
This PR adds openCypher-compatible relationship-type alternation in MATCH patterns (e.g. ()-[:A|B]->()), by extending the Cypher grammar/AST and injecting an additional edge-label filter qual during transformation to a PostgreSQL Query. It also explicitly rejects variable-length edges combined with alternation.
Changes:
- Extend the grammar and
cypher_relationshipAST node to represent multi-label edge patterns like[:A|B|C]. - During MATCH transformation, inject a synthetic qual restricting matched edges to the alternation’s label-id set.
- Add regression coverage for directed/undirected alternation, unknown labels, and the VLE rejection case.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/include/nodes/cypher_nodes.h | Adds labels list to cypher_relationship to represent relationship-type alternation. |
| src/backend/parser/cypher_gram.y | Parses `[:A |
| src/backend/parser/cypher_clause.c | Injects an IN qual over _extract_label_id(edge.id) for alternation; rejects alternation with VLE. |
| src/backend/nodes/cypher_outfuncs.c | Serializes the new labels field for cypher_relationship. |
| regress/sql/cypher_match_rel_label_alternation.sql | Adds regression test cases covering alternation behavior and the VLE rejection. |
| regress/expected/cypher_match_rel_label_alternation.out | Expected output for the new regression test. |
| Makefile | Registers the new regression test in REGRESS. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (id_consts == NIL) | ||
| { | ||
| return make_bool_a_const(false); | ||
| } |
|
Hitting it tomorrow |
|
@eeshwarg Please look at Copilot's suggestions. Additionally, how could this impact performance? |
In short, this shouldn't affect performance of already supported queries, but only adds support for a new query shape. All the code changes are during plan generation, not execution time. Existing query shapes take an unchanged code path - the multi-label logic is gated behind list_length(labels) > 1, which is false for every single-label/unlabeled pattern, so they produce an identical Query tree and therefore an identical plan. The new path adds a single integer IN filter on a scan that already existed, with all label resolution done at plan time. |
Apache AGE's MATCH grammar rejects openCypher's relationship-type alternation syntax -
MATCH ()-[:A|B]->()fails at parse time withsyntax error at or near "|". For example, a query likeSELECT * FROM cypher('kg_s7', $$ MATCH (p)-[:WORKS_AT|REPORTS_TO]->(c) RETURN c $$) AS (c agtype);throws a syntax error. A workaround for this today is to run something likeSELECT * FROM cypher('kg_s7', $$ MATCH (p)-[r]->(c) WHERE type(r) IN ['WORKS_AT','REPORTS_TO'] RETURN c $$) AS (c agtype);.This change enables support for relationship-type alternation in accordance with the openCypher standard. Changes are made in the grammar, AST and during transformation from the AST to Postgres
Querystruct by adding the types to thequalslist.Variable-length relationship patterns with alternation
([:A|B*1..2])are explicitly rejected withERRCODE_FEATURE_NOT_SUPPORTED.Testing:
Future work: