From 117803f83dca7dd1e8b29d513be496f1dd80f86f Mon Sep 17 00:00:00 2001 From: Dehowe Feng Date: Fri, 10 Mar 2023 16:42:41 +0900 Subject: [PATCH] Prevent MATCH from following OPTIONAL MATCH Added logic to prevent match from following optional match. This syntax is considered invalid, add logic to throw an error when this happens. Also added regression tests to test this logic. --- regress/expected/cypher_match.out | 19 +++++++++++++++++++ regress/sql/cypher_match.sql | 14 ++++++++++++++ src/backend/parser/cypher_clause.c | 17 +++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/regress/expected/cypher_match.out b/regress/expected/cypher_match.out index 8f325cbe6..4888556d9 100644 --- a/regress/expected/cypher_match.out +++ b/regress/expected/cypher_match.out @@ -1256,6 +1256,25 @@ SELECT * FROM cypher('cypher_match', $$ "nobody" | | | "anybody" | | (12 rows) +-- Tests to catch match following optional match logic +-- this syntax is invalid in cypher +SELECT * FROM cypher('cypher_match', $$ + OPTIONAL MATCH (n) + MATCH (m) + RETURN n,m + $$) AS (n agtype, m agtype); +ERROR: MATCH cannot follow OPTIONAL MATCH +LINE 1: SELECT * FROM cypher('cypher_match', $$ + ^ +SELECT * FROM cypher('cypher_match', $$ + MATCH (n) + OPTIONAL MATCH (m) + MATCH (o) + RETURN n,m + $$) AS (n agtype, m agtype); +ERROR: MATCH cannot follow OPTIONAL MATCH +LINE 1: SELECT * FROM cypher('cypher_match', $$ + ^ -- -- Tests retrieving Var from some parent's cpstate during transformation -- diff --git a/regress/sql/cypher_match.sql b/regress/sql/cypher_match.sql index 70f638df2..344453e00 100644 --- a/regress/sql/cypher_match.sql +++ b/regress/sql/cypher_match.sql @@ -621,6 +621,20 @@ SELECT * FROM cypher('cypher_match', $$ ORDER BY n, p, m, q $$) AS (n agtype, r agtype, p agtype, m agtype, s agtype, q agtype); +-- Tests to catch match following optional match logic +-- this syntax is invalid in cypher +SELECT * FROM cypher('cypher_match', $$ + OPTIONAL MATCH (n) + MATCH (m) + RETURN n,m + $$) AS (n agtype, m agtype); + +SELECT * FROM cypher('cypher_match', $$ + MATCH (n) + OPTIONAL MATCH (m) + MATCH (o) + RETURN n,m + $$) AS (n agtype, m agtype); -- -- Tests retrieving Var from some parent's cpstate during transformation diff --git a/src/backend/parser/cypher_clause.c b/src/backend/parser/cypher_clause.c index e1e6c94be..294ebb064 100644 --- a/src/backend/parser/cypher_clause.c +++ b/src/backend/parser/cypher_clause.c @@ -2508,6 +2508,23 @@ static Query *transform_cypher_match_pattern(cypher_parsestate *cpstate, query = makeNode(Query); query->commandType = CMD_SELECT; + if(self->optional == true && clause->next) + { + cypher_clause *next = clause->next; + if (is_ag_node(next->self, cypher_match)) + { + cypher_match *next_self = (cypher_match *)next->self; + if (!next_self->optional) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("MATCH cannot follow OPTIONAL MATCH"), + parser_errposition(pstate, + exprLocation((Node *) next_self)))); + } + } + } + // If there is no previous clause, transform to a general MATCH clause. if (self->optional == true && clause->prev != NULL) {