You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@age.apache.org by jo...@apache.org on 2021/11/30 22:36:16 UTC
[incubator-age] branch master updated: Fix wrong parse tree when use EXISTS PATTERN (#141)
This is an automated email from the ASF dual-hosted git repository.
joshinnis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-age.git
The following commit(s) were added to refs/heads/master by this push:
new 0b9205a Fix wrong parse tree when use EXISTS PATTERN (#141)
0b9205a is described below
commit 0b9205a72ad0363eb052301bb8ba775da4cc650f
Author: Alex Kwak <ta...@kakao.com>
AuthorDate: Wed Dec 1 07:36:09 2021 +0900
Fix wrong parse tree when use EXISTS PATTERN (#141)
EXISTS PATTERN used ParseState as it was and affected the upper query.
Use a temporary ParseState to solve this problem.
---
regress/expected/cypher_match.out | 88 ++++++++++++++++++++++++++++++++++++++
regress/sql/cypher_match.sql | 43 +++++++++++++++++++
src/backend/parser/cypher_clause.c | 26 ++++++-----
3 files changed, 147 insertions(+), 10 deletions(-)
diff --git a/regress/expected/cypher_match.out b/regress/expected/cypher_match.out
index 1590af9..f1bb3d7 100644
--- a/regress/expected/cypher_match.out
+++ b/regress/expected/cypher_match.out
@@ -890,6 +890,94 @@ $$) AS (i agtype);
(3 rows)
--
+-- JIRA: AGE2-544
+--
+-- Clean up
+SELECT DISTINCT * FROM cypher('cypher_match', $$
+ MATCH (u) DETACH DELETE (u)
+$$) AS (i agtype);
+ i
+---
+(0 rows)
+
+-- Prepare
+SELECT * FROM cypher('cypher_match', $$
+ CREATE (u {name: "orphan"})
+ CREATE (u1 {name: "F"})-[u2:e1]->(u3 {name: "T"})
+ RETURN u1, u2, u3
+$$) as (u1 agtype, u2 agtype, u3 agtype);
+ u1 | u2 | u3
+---------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------
+ {"id": 281474976710660, "label": "", "properties": {"name": "F"}}::vertex | {"id": 1407374883553283, "label": "e1", "end_id": 281474976710661, "start_id": 281474976710660, "properties": {}}::edge | {"id": 281474976710661, "label": "", "properties": {"name": "T"}}::vertex
+(1 row)
+
+-- Querying NOT EXISTS syntax
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (f),(t)
+ WHERE NOT EXISTS((f)-[]->(t))
+ RETURN f.name, t.name
+ $$) as (f agtype, t agtype);
+ f | t
+----------+----------
+ "orphan" | "orphan"
+ "orphan" | "F"
+ "orphan" | "T"
+ "F" | "orphan"
+ "F" | "F"
+ "T" | "orphan"
+ "T" | "F"
+ "T" | "T"
+(8 rows)
+
+-- Querying EXISTS syntax
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (f),(t)
+ WHERE EXISTS((f)-[]->(t))
+ RETURN f.name, t.name
+ $$) as (f agtype, t agtype);
+ f | t
+-----+-----
+ "F" | "T"
+(1 row)
+
+-- Querying ALL
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (f),(t)
+ WHERE NOT EXISTS((f)-[]->(t)) or true
+ RETURN f.name, t.name
+$$) as (f agtype, t agtype);
+ f | t
+----------+----------
+ "orphan" | "orphan"
+ "orphan" | "F"
+ "orphan" | "T"
+ "F" | "orphan"
+ "F" | "F"
+ "F" | "T"
+ "T" | "orphan"
+ "T" | "F"
+ "T" | "T"
+(9 rows)
+
+-- Querying ALL
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (f),(t)
+ RETURN f.name, t.name
+$$) as (f agtype, t agtype);
+ f | t
+----------+----------
+ "orphan" | "orphan"
+ "orphan" | "F"
+ "orphan" | "T"
+ "F" | "orphan"
+ "F" | "F"
+ "F" | "T"
+ "T" | "orphan"
+ "T" | "F"
+ "T" | "T"
+(9 rows)
+
+--
-- Clean up
--
SELECT drop_graph('cypher_match', true);
diff --git a/regress/sql/cypher_match.sql b/regress/sql/cypher_match.sql
index 377dc40..686d6ee 100644
--- a/regress/sql/cypher_match.sql
+++ b/regress/sql/cypher_match.sql
@@ -457,6 +457,49 @@ SELECT * FROM cypher('cypher_match', $$
$$) AS (i agtype);
--
+-- JIRA: AGE2-544
+--
+
+-- Clean up
+SELECT DISTINCT * FROM cypher('cypher_match', $$
+ MATCH (u) DETACH DELETE (u)
+$$) AS (i agtype);
+
+-- Prepare
+SELECT * FROM cypher('cypher_match', $$
+ CREATE (u {name: "orphan"})
+ CREATE (u1 {name: "F"})-[u2:e1]->(u3 {name: "T"})
+ RETURN u1, u2, u3
+$$) as (u1 agtype, u2 agtype, u3 agtype);
+
+-- Querying NOT EXISTS syntax
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (f),(t)
+ WHERE NOT EXISTS((f)-[]->(t))
+ RETURN f.name, t.name
+ $$) as (f agtype, t agtype);
+
+-- Querying EXISTS syntax
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (f),(t)
+ WHERE EXISTS((f)-[]->(t))
+ RETURN f.name, t.name
+ $$) as (f agtype, t agtype);
+
+-- Querying ALL
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (f),(t)
+ WHERE NOT EXISTS((f)-[]->(t)) or true
+ RETURN f.name, t.name
+$$) as (f agtype, t agtype);
+
+-- Querying ALL
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (f),(t)
+ RETURN f.name, t.name
+$$) as (f agtype, t agtype);
+
+--
-- Clean up
--
SELECT drop_graph('cypher_match', true);
diff --git a/src/backend/parser/cypher_clause.c b/src/backend/parser/cypher_clause.c
index a7fbf13..e9aaaff 100644
--- a/src/backend/parser/cypher_clause.c
+++ b/src/backend/parser/cypher_clause.c
@@ -1279,6 +1279,10 @@ static Query *transform_cypher_sub_pattern(cypher_parsestate *cpstate,
ParseState *pstate = (ParseState *)cpstate;
cypher_sub_pattern *subpat = (cypher_sub_pattern*)clause->self;
+ cypher_parsestate *child_parse_state = make_cypher_parsestate(cpstate);
+ ParseState *p_child_parse_state = (ParseState *) child_parse_state;
+ p_child_parse_state->p_expr_kind = pstate->p_expr_kind;
+
/* create a cypher match node and assign it the sub pattern */
match = make_ag_node(cypher_match);
match->pattern = subpat->pattern;
@@ -1293,25 +1297,27 @@ static Query *transform_cypher_sub_pattern(cypher_parsestate *cpstate,
qry = makeNode(Query);
qry->commandType = CMD_SELECT;
- rte = transform_cypher_clause_as_subquery(cpstate, transform_cypher_clause,
+ rte = transform_cypher_clause_as_subquery(child_parse_state, transform_cypher_clause,
c);
- qry->targetList = makeTargetListFromRTE(pstate, rte);
+ qry->targetList = makeTargetListFromRTE(p_child_parse_state, rte);
- markTargetListOrigins(pstate, qry->targetList);
+ markTargetListOrigins(p_child_parse_state, qry->targetList);
- qry->rtable = pstate->p_rtable;
- qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
+ qry->rtable = p_child_parse_state->p_rtable;
+ qry->jointree = makeFromExpr(p_child_parse_state->p_joinlist, NULL);
/* the state will be destroyed so copy the data we need */
- qry->hasSubLinks = pstate->p_hasSubLinks;
- qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
- qry->hasAggs = pstate->p_hasAggs;
+ qry->hasSubLinks = p_child_parse_state->p_hasSubLinks;
+ qry->hasTargetSRFs = p_child_parse_state->p_hasTargetSRFs;
+ qry->hasAggs = p_child_parse_state->p_hasAggs;
if (qry->hasAggs)
- parse_check_aggregates(pstate, qry);
+ parse_check_aggregates(p_child_parse_state, qry);
+
+ assign_query_collations(p_child_parse_state, qry);
- assign_query_collations(pstate, qry);
+ free_cypher_parsestate(child_parse_state);
return qry;
}