This is an automated email from the ASF dual-hosted git repository.
dehowef pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/age.git
The following commit(s) were added to refs/heads/master by this push:
new 9df285ad Fix multiple label name usage in reused variables (#916)
9df285ad is described below
commit 9df285addeb6a9f8ef06246d244b732b62b641cf
Author: John Gemignani <[email protected]>
AuthorDate: Thu May 18 15:00:14 2023 -0700
Fix multiple label name usage in reused variables (#916)
Fixed an issue with clauses and chained clauses reusing variables
with a different label name attached. Now they are disallowed. A
variable can only have one label.
Added logic to pass variable label names into the nodes and edges
that reference them. This is only for the nodes and edges that don't
specify a label name and that reference already defined variables.
This makes it easier to verify that the nodes or edges are using
the correct label names.
Fixed the function prototypes make_vertex_expr and make_edge_expr
as they were not using the passed char *label parameter.
Added and adjusted regression tests.
---
regress/expected/cypher_match.out | 288 +++++++++++++++++++++++++++--
regress/sql/cypher_match.sql | 122 ++++++++++++-
src/backend/parser/cypher_clause.c | 361 ++++++++++++++++++++++++-------------
src/backend/parser/cypher_gram.y | 3 +
src/include/nodes/cypher_nodes.h | 2 +
5 files changed, 629 insertions(+), 147 deletions(-)
diff --git a/regress/expected/cypher_match.out
b/regress/expected/cypher_match.out
index c7a9b305..1f97ef49 100644
--- a/regress/expected/cypher_match.out
+++ b/regress/expected/cypher_match.out
@@ -545,13 +545,282 @@ $$) AS (a agtype);
ERROR: multiple labels for variable 'a' are not supported
LINE 2: MATCH (a) MATCH (a:invalid_label) RETURN a
^
---Valid variable reuse, although why would you want to do it this way?
SELECT * FROM cypher('cypher_match', $$
MATCH (a:v1)-[]-()-[a]-() RETURN a
$$) AS (a agtype);
ERROR: variable 'a' is for a vertex
LINE 2: MATCH (a:v1)-[]-()-[a]-() RETURN a
^
+-- valid variable reuse for edge labels across clauses
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0]->() MATCH ()-[r0]->() RETURN r0
+$$) AS (r0 agtype);
+ r0
+---------------------------------------------------------------------------------------------------------------------------
+ {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge
+ {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge
+ {"id": 1970324836974593, "label": "e2", "end_id": 1688849860263939,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 1970324836974594, "label": "e2", "end_id": 1688849860263937,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 2533274790395905, "label": "e3", "end_id": 2251799813685250,
"start_id": 2251799813685251, "properties": {}}::edge
+ {"id": 2533274790395906, "label": "e3", "end_id": 2251799813685250,
"start_id": 2251799813685249, "properties": {}}::edge
+(6 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->() MATCH ()-[r0:e1]->() RETURN r0
+$$) AS (r0 agtype);
+ r0
+---------------------------------------------------------------------------------------------------------------------------
+ {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge
+ {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge
+(2 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e2]->() MATCH ()-[r0:e2]->() RETURN r0
+$$) AS (r0 agtype);
+ r0
+---------------------------------------------------------------------------------------------------------------------------
+ {"id": 1970324836974593, "label": "e2", "end_id": 1688849860263939,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 1970324836974594, "label": "e2", "end_id": 1688849860263937,
"start_id": 1688849860263938, "properties": {}}::edge
+(2 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->()-[r1]->() RETURN r0,r1
+$$) AS (r0 agtype, r1 agtype);
+ r0
|
r1
+---------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------
+ {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge | {"id":
1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id":
1125899906842626, "properties": {}}::edge
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH p0=()-[:e1]->() MATCH p1=()-[:e2]->() RETURN p1
+$$) AS (p1 agtype);
+
p1
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1688849860263938, "label": "v2", "properties": {"id":
"middle"}}::vertex, {"id": 1970324836974594, "label": "e2", "end_id":
1688849860263937, "start_id": 1688849860263938, "properties": {}}::edge, {"id":
1688849860263937, "label": "v2", "properties": {"id": "initial"}}::vertex]::path
+ [{"id": 1688849860263938, "label": "v2", "properties": {"id":
"middle"}}::vertex, {"id": 1970324836974594, "label": "e2", "end_id":
1688849860263937, "start_id": 1688849860263938, "properties": {}}::edge, {"id":
1688849860263937, "label": "v2", "properties": {"id": "initial"}}::vertex]::path
+ [{"id": 1688849860263938, "label": "v2", "properties": {"id":
"middle"}}::vertex, {"id": 1970324836974593, "label": "e2", "end_id":
1688849860263939, "start_id": 1688849860263938, "properties": {}}::edge, {"id":
1688849860263939, "label": "v2", "properties": {"id": "end"}}::vertex]::path
+ [{"id": 1688849860263938, "label": "v2", "properties": {"id":
"middle"}}::vertex, {"id": 1970324836974593, "label": "e2", "end_id":
1688849860263939, "start_id": 1688849860263938, "properties": {}}::edge, {"id":
1688849860263939, "label": "v2", "properties": {"id": "end"}}::vertex]::path
+(4 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->()-[r1]->() MATCH ()-[r0:e1]->()-[r1]->() RETURN
r0,r1
+$$) AS (r0 agtype, r1 agtype);
+ r0
|
r1
+---------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------
+ {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge | {"id":
1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id":
1125899906842626, "properties": {}}::edge
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[]->() MATCH ()-[r1:e2]->() RETURN r1
+$$) AS (r1 agtype);
+ r1
+---------------------------------------------------------------------------------------------------------------------------
+ {"id": 1970324836974593, "label": "e2", "end_id": 1688849860263939,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 1970324836974594, "label": "e2", "end_id": 1688849860263937,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 1970324836974593, "label": "e2", "end_id": 1688849860263939,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 1970324836974594, "label": "e2", "end_id": 1688849860263937,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 1970324836974593, "label": "e2", "end_id": 1688849860263939,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 1970324836974594, "label": "e2", "end_id": 1688849860263937,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 1970324836974593, "label": "e2", "end_id": 1688849860263939,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 1970324836974594, "label": "e2", "end_id": 1688849860263937,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 1970324836974593, "label": "e2", "end_id": 1688849860263939,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 1970324836974594, "label": "e2", "end_id": 1688849860263937,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 1970324836974593, "label": "e2", "end_id": 1688849860263939,
"start_id": 1688849860263938, "properties": {}}::edge
+ {"id": 1970324836974594, "label": "e2", "end_id": 1688849860263937,
"start_id": 1688849860263938, "properties": {}}::edge
+(12 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->() MATCH ()-[r1:e2]->() RETURN r0,r1
+$$) AS (r0 agtype, r1 agtype);
+ r0
|
r1
+---------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------
+ {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge | {"id":
1970324836974593, "label": "e2", "end_id": 1688849860263939, "start_id":
1688849860263938, "properties": {}}::edge
+ {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge | {"id":
1970324836974594, "label": "e2", "end_id": 1688849860263937, "start_id":
1688849860263938, "properties": {}}::edge
+ {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge | {"id":
1970324836974593, "label": "e2", "end_id": 1688849860263939, "start_id":
1688849860263938, "properties": {}}::edge
+ {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge | {"id":
1970324836974594, "label": "e2", "end_id": 1688849860263937, "start_id":
1688849860263938, "properties": {}}::edge
+(4 rows)
+
+-- valid variable reuse for vertex labels across clauses
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid), (r1:invalid) return r1
+$$) AS (r1 agtype);
+ r1
+----
+(0 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1), (r1) return r1
+$$) AS (r1 agtype);
+
r1
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 281474976710657, "label": "", "properties": {"int_key": 1, "map_key":
{"key": "value"}, "list_key": [1, 2, 3], "float_key": 3.14, "string_key":
"test"}}::vertex
+ {"id": 281474976710658, "label": "", "properties": {"lst": [1, null, 3.14,
"string", {"key": "value"}, []]}}::vertex
+ {"id": 844424930131969, "label": "v", "properties": {}}::vertex
+ {"id": 844424930131970, "label": "v", "properties": {"i": 0}}::vertex
+ {"id": 844424930131971, "label": "v", "properties": {"i": 1}}::vertex
+ {"id": 1125899906842625, "label": "v1", "properties": {"id":
"initial"}}::vertex
+ {"id": 1125899906842626, "label": "v1", "properties": {"id":
"middle"}}::vertex
+ {"id": 1125899906842627, "label": "v1", "properties": {"id": "end"}}::vertex
+ {"id": 1688849860263937, "label": "v2", "properties": {"id":
"initial"}}::vertex
+ {"id": 1688849860263938, "label": "v2", "properties": {"id":
"middle"}}::vertex
+ {"id": 1688849860263939, "label": "v2", "properties": {"id": "end"}}::vertex
+ {"id": 2251799813685249, "label": "v3", "properties": {"id":
"initial"}}::vertex
+ {"id": 2251799813685250, "label": "v3", "properties": {"id":
"middle"}}::vertex
+ {"id": 2251799813685251, "label": "v3", "properties": {"id": "end"}}::vertex
+(14 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid), (r1) return r1
+$$) AS (r1 agtype);
+ r1
+----
+(0 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid), (r1), (r1), (r1:invalid) return r1
+$$) AS (r1 agtype);
+ r1
+----
+(0 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid)-[]->(r1)-[]->(r1:invalid)-[]->(r1) return r1
+$$) AS (r1 agtype);
+ r1
+----
+(0 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid)-[]->()-[]->()-[]->(r1:invalid) return r1
+$$) AS (r1 agtype);
+ r1
+----
+(0 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->()-[r1]->() MATCH ()-[r0:e1]->()-[r0]->() RETURN r0
+$$) AS (r0 agtype);
+ r0
+----
+(0 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->() MATCH ()-[r0]->() RETURN r0
+$$) AS (r0 agtype);
+ r0
+---------------------------------------------------------------------------------------------------------------------------
+ {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge
+ {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge
+(2 rows)
+
+-- invalid variable reuse for vertex
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid)-[]->(r1)-[]->(r1)-[]->(r1:invalids) return r1
+$$) AS (r1 agtype);
+ERROR: multiple labels for variable 'r1' are not supported
+LINE 2: MATCH (r1:invalid)-[]->(r1)-[]->(r1)-[]->(r1:invali...
+ ^
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid)-[]->(r1)-[]->(r1)-[]->(r1)-[r1]->() return r1
+$$) AS (r1 agtype);
+ERROR: variable 'r1' is for a vertex
+LINE 2: ... MATCH (r1:invalid)-[]->(r1)-[]->(r1)-[]->(r1)-[r1]->() r...
+ ^
+-- invalid variable reuse for labels across clauses
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:e1), (r1:e2) return r1
+$$) AS (r1 agtype);
+ERROR: multiple labels for variable 'r1' are not supported
+LINE 2: MATCH (r1:e1), (r1:e2) return r1
+ ^
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid), (r1:e2) return r1
+$$) AS (r1 agtype);
+ERROR: multiple labels for variable 'r1' are not supported
+LINE 2: MATCH (r1:invalid), (r1:e2) return r1
+ ^
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:e1), (r1:invalid) return r1
+$$) AS (r1 agtype);
+ERROR: multiple labels for variable 'r1' are not supported
+LINE 2: MATCH (r1:e1), (r1:invalid) return r1
+ ^
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:e1), (r1), (r1:invalid) return r1
+$$) AS (r1 agtype);
+ERROR: multiple labels for variable 'r1' are not supported
+LINE 2: MATCH (r1:e1), (r1), (r1:invalid) return r1
+ ^
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r0)-[r0]->() MATCH ()-[]->() RETURN r0
+$$) AS (r0 agtype);
+ERROR: variable 'r0' is for a vertex
+LINE 2: MATCH (r0)-[r0]->() MATCH ()-[]->() RETURN r0
+ ^
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r0)-[]->() MATCH ()-[r0]->() RETURN r0
+$$) AS (r0 agtype);
+ERROR: variable 'r0' is for a vertex
+LINE 2: MATCH (r0)-[]->() MATCH ()-[r0]->() RETURN r0
+ ^
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0]->() MATCH ()-[]->(r0) RETURN r0
+$$) AS (r0 agtype);
+ERROR: variable 'r0' is for a edge
+LINE 2: MATCH ()-[r0]->() MATCH ()-[]->(r0) RETURN r0
+ ^
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->() MATCH ()-[r0:e2]->() RETURN r0
+$$) AS (r0 agtype);
+ERROR: multiple labels for variable 'r0' are not supported
+LINE 2: MATCH ()-[r0:e1]->() MATCH ()-[r0:e2]->() RETURN r0
+ ^
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0]->() MATCH ()-[r0:e2]->() RETURN r0
+$$) AS (r0 agtype);
+ERROR: multiple labels for variable 'r0' are not supported
+LINE 2: MATCH ()-[r0]->() MATCH ()-[r0:e2]->() RETURN r0
+ ^
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->() MATCH ()-[r0:e2]->() RETURN r0
+$$) AS (r0 agtype);
+ERROR: multiple labels for variable 'r0' are not supported
+LINE 2: MATCH ()-[r0:e1]->() MATCH ()-[r0:e2]->() RETURN r0
+ ^
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->()-[r0]->() MATCH ()-[r0:e2]->() RETURN r0
+$$) AS (r0 agtype);
+ERROR: duplicate edge variable 'r0' within a clause
+LINE 2: MATCH ()-[r0:e1]->()-[r0]->() MATCH ()-[r0:e2]->() R...
+ ^
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->()-[r1]->() MATCH ()-[r1:e1]->()-[r0]->() RETURN r0
+$$) AS (r0 agtype);
+ERROR: multiple labels for variable 'r1' are not supported
+LINE 2: MATCH ()-[r0:e1]->()-[r1]->() MATCH ()-[r1:e1]->()-[...
+ ^
+-- Labels that don't exist but do match
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r0)-[r1:related]->() MATCH ()-[r1:related]->() RETURN r0
+$$) AS (r0 agtype);
+ r0
+----
+(0 rows)
+
+-- Labels that don't exist and don't match
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r0)-[r1]->() MATCH ()-[r1:related]->() RETURN r0
+$$) AS (r0 agtype);
+ERROR: multiple labels for variable 'r1' are not supported
+LINE 2: MATCH (r0)-[r1]->() MATCH ()-[r1:related]->() RETURN...
+ ^
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r0)-[r1:related]->() MATCH ()-[r1:relateds]->() RETURN r0
+$$) AS (r0 agtype);
+ERROR: multiple labels for variable 'r1' are not supported
+LINE 2: MATCH (r0)-[r1:related]->() MATCH ()-[r1:relateds]->...
+ ^
+--Valid variable reuse, although why would you want to do it this way?
SELECT * FROM cypher('cypher_match', $$
MATCH (a:v1)-[]-()-[]-(a {id:'will_not_fail'}) RETURN a
$$) AS (a agtype);
@@ -726,15 +995,6 @@ AS (u agtype, e agtype, v agtype);
{"id": 2814749767106561, "label": "loop", "properties": {"id":
"initial"}}::vertex | {"id": 3096224743817217, "label": "self", "end_id":
2814749767106561, "start_id": 2814749767106561, "properties": {}}::edge |
{"id": 2814749767106561, "label": "loop", "properties": {"id":
"initial"}}::vertex
(1 row)
--- Exists checks for a loop. There should be none because of edge uniqueness
--- requirement.
-SELECT * FROM cypher('cypher_match',
- $$MATCH (u)-[e]->(v) WHERE EXISTS((u)-[e]->(u)-[e]->(u)) RETURN u, e, v $$)
-AS (u agtype, e agtype, v agtype);
- u | e | v
----+---+---
-(0 rows)
-
-- Multiple exists
SELECT * FROM cypher('cypher_match',
$$MATCH (u)-[e]->(v) WHERE EXISTS((u)) AND EXISTS((v)) RETURN u, e, v $$)
@@ -1770,14 +2030,14 @@ SELECT * FROM cypher('cypher_match', $$ MATCH p=(a
{name: "John"})-[]->()-[]->(a
(1 row)
-- these are illegal and should fail
-SELECT * FROM cypher('cypher_match', $$ MATCH p=(a)-[b]->()-[b]->(a) RETURN p
$$)as (p agtype);
-ERROR: duplicate edge variable 'b' within a clause
-LINE 1: ...ROM cypher('cypher_match', $$ MATCH p=(a)-[b]->()-[b]->(a) R...
- ^
SELECT * FROM cypher('cypher_match', $$ MATCH p=(a)-[b]->()-[b:knows]->(a)
RETURN p $$)as (p agtype);
ERROR: duplicate edge variable 'b' within a clause
LINE 1: ...ROM cypher('cypher_match', $$ MATCH p=(a)-[b]->()-[b:knows]-...
^
+SELECT * FROM cypher('cypher_match', $$ MATCH p=(a)-[b]->()-[b]->(a) RETURN p
$$)as (p agtype);
+ERROR: duplicate edge variable 'b' within a clause
+LINE 1: ...ROM cypher('cypher_match', $$ MATCH p=(a)-[b]->()-[b]->(a) R...
+ ^
SELECT * FROM cypher('cypher_match', $$ MATCH
p=(a)-[b:knows]->()-[b:knows]->(a) RETURN p $$)as (p agtype);
ERROR: duplicate edge variable 'b' within a clause
LINE 1: ...pher('cypher_match', $$ MATCH p=(a)-[b:knows]->()-[b:knows]-...
diff --git a/regress/sql/cypher_match.sql b/regress/sql/cypher_match.sql
index 60931f60..6829d16f 100644
--- a/regress/sql/cypher_match.sql
+++ b/regress/sql/cypher_match.sql
@@ -293,12 +293,122 @@ $$) AS (a agtype);
SELECT * FROM cypher('cypher_match', $$
MATCH (a) MATCH (a:invalid_label) RETURN a
$$) AS (a agtype);
-
---Valid variable reuse, although why would you want to do it this way?
SELECT * FROM cypher('cypher_match', $$
MATCH (a:v1)-[]-()-[a]-() RETURN a
$$) AS (a agtype);
+-- valid variable reuse for edge labels across clauses
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0]->() MATCH ()-[r0]->() RETURN r0
+$$) AS (r0 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->() MATCH ()-[r0:e1]->() RETURN r0
+$$) AS (r0 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e2]->() MATCH ()-[r0:e2]->() RETURN r0
+$$) AS (r0 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->()-[r1]->() RETURN r0,r1
+$$) AS (r0 agtype, r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH p0=()-[:e1]->() MATCH p1=()-[:e2]->() RETURN p1
+$$) AS (p1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->()-[r1]->() MATCH ()-[r0:e1]->()-[r1]->() RETURN
r0,r1
+$$) AS (r0 agtype, r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[]->() MATCH ()-[r1:e2]->() RETURN r1
+$$) AS (r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->() MATCH ()-[r1:e2]->() RETURN r0,r1
+$$) AS (r0 agtype, r1 agtype);
+
+-- valid variable reuse for vertex labels across clauses
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid), (r1:invalid) return r1
+$$) AS (r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1), (r1) return r1
+$$) AS (r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid), (r1) return r1
+$$) AS (r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid), (r1), (r1), (r1:invalid) return r1
+$$) AS (r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid)-[]->(r1)-[]->(r1:invalid)-[]->(r1) return r1
+$$) AS (r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid)-[]->()-[]->()-[]->(r1:invalid) return r1
+$$) AS (r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->()-[r1]->() MATCH ()-[r0:e1]->()-[r0]->() RETURN r0
+$$) AS (r0 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->() MATCH ()-[r0]->() RETURN r0
+$$) AS (r0 agtype);
+
+-- invalid variable reuse for vertex
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid)-[]->(r1)-[]->(r1)-[]->(r1:invalids) return r1
+$$) AS (r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid)-[]->(r1)-[]->(r1)-[]->(r1)-[r1]->() return r1
+$$) AS (r1 agtype);
+
+-- invalid variable reuse for labels across clauses
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:e1), (r1:e2) return r1
+$$) AS (r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:invalid), (r1:e2) return r1
+$$) AS (r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:e1), (r1:invalid) return r1
+$$) AS (r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r1:e1), (r1), (r1:invalid) return r1
+$$) AS (r1 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r0)-[r0]->() MATCH ()-[]->() RETURN r0
+$$) AS (r0 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r0)-[]->() MATCH ()-[r0]->() RETURN r0
+$$) AS (r0 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0]->() MATCH ()-[]->(r0) RETURN r0
+$$) AS (r0 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->() MATCH ()-[r0:e2]->() RETURN r0
+$$) AS (r0 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0]->() MATCH ()-[r0:e2]->() RETURN r0
+$$) AS (r0 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->() MATCH ()-[r0:e2]->() RETURN r0
+$$) AS (r0 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->()-[r0]->() MATCH ()-[r0:e2]->() RETURN r0
+$$) AS (r0 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH ()-[r0:e1]->()-[r1]->() MATCH ()-[r1:e1]->()-[r0]->() RETURN r0
+$$) AS (r0 agtype);
+
+-- Labels that don't exist but do match
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r0)-[r1:related]->() MATCH ()-[r1:related]->() RETURN r0
+$$) AS (r0 agtype);
+
+-- Labels that don't exist and don't match
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r0)-[r1]->() MATCH ()-[r1:related]->() RETURN r0
+$$) AS (r0 agtype);
+SELECT * FROM cypher('cypher_match', $$
+ MATCH (r0)-[r1:related]->() MATCH ()-[r1:relateds]->() RETURN r0
+$$) AS (r0 agtype);
+
+--Valid variable reuse, although why would you want to do it this way?
SELECT * FROM cypher('cypher_match', $$
MATCH (a:v1)-[]-()-[]-(a {id:'will_not_fail'}) RETURN a
$$) AS (a agtype);
@@ -376,12 +486,6 @@ SELECT * FROM cypher('cypher_match',
$$MATCH (u)-[e]->(v) WHERE EXISTS((v)-[e]->(v)) RETURN u, e, v $$)
AS (u agtype, e agtype, v agtype);
--- Exists checks for a loop. There should be none because of edge uniqueness
--- requirement.
-SELECT * FROM cypher('cypher_match',
- $$MATCH (u)-[e]->(v) WHERE EXISTS((u)-[e]->(u)-[e]->(u)) RETURN u, e, v $$)
-AS (u agtype, e agtype, v agtype);
-
-- Multiple exists
SELECT * FROM cypher('cypher_match',
$$MATCH (u)-[e]->(v) WHERE EXISTS((u)) AND EXISTS((v)) RETURN u, e, v $$)
@@ -837,8 +941,8 @@ SELECT * FROM cypher('cypher_match', $$ MATCH p=(a {name:
"Dave"})-[]->()-[]->(a
SELECT * FROM cypher('cypher_match', $$ MATCH p=(a {name:
"John"})-[]->()-[]->(a) RETURN p $$)as (p agtype);
-- these are illegal and should fail
-SELECT * FROM cypher('cypher_match', $$ MATCH p=(a)-[b]->()-[b]->(a) RETURN p
$$)as (p agtype);
SELECT * FROM cypher('cypher_match', $$ MATCH p=(a)-[b]->()-[b:knows]->(a)
RETURN p $$)as (p agtype);
+SELECT * FROM cypher('cypher_match', $$ MATCH p=(a)-[b]->()-[b]->(a) RETURN p
$$)as (p agtype);
SELECT * FROM cypher('cypher_match', $$ MATCH
p=(a)-[b:knows]->()-[b:knows]->(a) RETURN p $$)as (p agtype);
SELECT * FROM cypher('cypher_match', $$ MATCH p=(a)-[b:knows]->()-[b]->(a)
RETURN p $$)as (p agtype);
diff --git a/src/backend/parser/cypher_clause.c
b/src/backend/parser/cypher_clause.c
index ad8821a2..18cf3c63 100644
--- a/src/backend/parser/cypher_clause.c
+++ b/src/backend/parser/cypher_clause.c
@@ -133,10 +133,8 @@ static Expr *transform_cypher_edge(cypher_parsestate
*cpstate,
static Expr *transform_cypher_node(cypher_parsestate *cpstate,
cypher_node *node, List **target_list,
bool output_node, bool valid_label);
-static Node *make_vertex_expr(cypher_parsestate *cpstate, RangeTblEntry *rte,
- char *label);
-static Node *make_edge_expr(cypher_parsestate *cpstate, RangeTblEntry *rte,
- char *label);
+static Node *make_vertex_expr(cypher_parsestate *cpstate, RangeTblEntry *rte);
+static Node *make_edge_expr(cypher_parsestate *cpstate, RangeTblEntry *rte);
static Node *make_qual(cypher_parsestate *cpstate,
transform_entity *entity, char *name);
static TargetEntry *
@@ -3819,13 +3817,13 @@ static List *transform_match_entities(cypher_parsestate
*cpstate, Query *query,
entity = make_transform_entity(cpstate, ENT_VERTEX, (Node *)node,
expr);
- /*
+ /*
* We want to add tranformed entity to entities before tranforming
props
* so that props referncing currently transformed entity can be
resolved.
*/
cpstate->entities = lappend(cpstate->entities, entity);
entities = lappend(entities, entity);
-
+
/* transform the properties if they exist */
if (node->props)
{
@@ -3939,7 +3937,7 @@ static List *transform_match_entities(cypher_parsestate
*cpstate, Query *query,
entity = make_transform_entity(cpstate, ENT_EDGE, (Node *)rel,
expr);
- /*
+ /*
* We want to add tranformed entity to entities before
tranforming props
* so that props referncing currently transformed entity can
be resolved.
*/
@@ -4284,40 +4282,135 @@ static Expr *transform_cypher_edge(cypher_parsestate
*cpstate,
bool valid_label)
{
ParseState *pstate = (ParseState *)cpstate;
- char *schema_name;
- char *rel_name;
- RangeVar *label_range_var;
- Alias *alias;
- RangeTblEntry *rte;
- int resno;
- TargetEntry *te;
- Expr *expr;
+ char *schema_name = NULL;
+ char *rel_name = NULL;
+ RangeVar *label_range_var = NULL;
+ Alias *alias = NULL;
+ RangeTblEntry *rte = NULL;
+ int resno = -1;
+ TargetEntry *te = NULL;
+ transform_entity *entity = NULL;
+ cypher_relationship *cr = NULL;
+ Node *expr = NULL;
+ bool refs_var = false;
- if (!rel->label)
+ /*
+ * If we have an edge name, get any potential variable or column
+ * references. Additionally, verify that they are for edges.
+ */
+ if (rel->name != NULL)
{
- rel->label = AG_DEFAULT_LABEL_EDGE;
+ te = findTarget(*target_list, rel->name);
+ entity = find_variable(cpstate, rel->name);
+ expr = colNameToVar(pstate, rel->name, false, rel->location);
+
+ /*
+ * If we have a valid entity and te for this rel name, go ahead and get
+ * the cypher relationship as we will need this for later and flag that
+ * we have a variable reference.
+ */
+ if (te != NULL && entity != NULL)
+ {
+ cr = (cypher_relationship *)entity->entity.rel;
+ refs_var = true;
+ }
+
+ /* If the variable already exists, verify that it is for an edge */
+ if (refs_var && entity->type != ENT_EDGE)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("variable '%s' is for a vertex", rel->name),
+ parser_errposition(pstate, rel->location)));
+ }
}
- else if(!valid_label)
+
+ /*
+ * If we do not have a label for this edge, we either need to find one
+ * from a referenced variable or we need to set it to the default label.
+ */
+ if (rel->label == NULL)
+ {
+ /* if there is a variable for this rel name */
+ if (refs_var)
+ {
+ /*
+ * If the referenced var has a non NULL label, copy it. This is
+ * usually the case when it uses a variable that is already
defined.
+ * Fx -
+ *
+ * MATCH (u:people)-[e:knows]->(v:people), (v)-[e]->(u) RETURN
e
+ * MATCH (u:people)-[]->()-[]->(u) RETURN u
+ *
+ * We copy it so that we know what label it is referencing.
+ */
+ if (cr->parsed_label != NULL)
+ {
+ rel->parsed_label = cr->parsed_label;
+ rel->label = cr->label;
+ }
+ else
+ {
+ rel->label = AG_DEFAULT_LABEL_EDGE;
+ }
+ }
+ /* otherwise, just give it the default label */
+ else
+ {
+ rel->label = AG_DEFAULT_LABEL_EDGE;
+ }
+ }
+ /* if we do have a label, is it valid */
+ else if (!valid_label)
{
/*
* XXX: Need to determine proper rules, for when label does not exist
- * or is for an edge. Maybe labels and edges should share names, like
+ * or is for an vertex. Maybe labels and edges should share names,
like
* in openCypher. But these are stand in errors, to prevent
* segmentation faults, and other errors.
*
* Update: Nonexistent and mismatched labels now return a NULL value
to
- * prevent segmentation faults, and other errors. We can also
consider
+ * prevent segmentation faults, and other errors. We can also consider
* if an all-purpose label would be useful.
*/
rel->label = NULL;
+ }
+ /*
+ * Variables for edges are not allowed to be used multiple times within the
+ * same clause.
+ */
+ if (expr == NULL && refs_var)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("duplicate edge variable '%s' within a clause",
+ rel->name),
+ parser_errposition(pstate, rel->location)));
}
- if (rel->name != NULL)
+ /*
+ * If this edge uses a variable that already exists, verify that the label
+ * names are the same.
+ */
+ if (refs_var &&
+ (cr->parsed_label != NULL || rel->parsed_label != NULL) &&
+ (cr->parsed_label == NULL || rel->parsed_label == NULL ||
+ (pg_strcasecmp(cr->parsed_label, rel->parsed_label) != 0)))
{
- TargetEntry *te;
- Node *expr;
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("multiple labels for variable '%s' are not supported",
+ rel->name),
+ parser_errposition(pstate, rel->location)));
+ }
+ /*
+ * Now we need to do a few checks and either return the existing var or
+ * or build a new edge.
+ */
+ if (rel->name != NULL)
+ {
/*
* If we are in a WHERE clause transform, we don't want to create new
* variables, we want to use the existing ones. So, error if otherwise.
@@ -4330,11 +4423,12 @@ static Expr *transform_cypher_edge(cypher_parsestate
*cpstate,
* If expr_kind is WHERE, the expressions are in the parent's
* parent's parsestate, due to the way we transform sublinks.
*/
- transform_entity *entity = find_variable(parent_cpstate,
rel->name);
+ transform_entity *tentity = find_variable(parent_cpstate,
+ rel->name);
- if (entity != NULL)
+ if (tentity != NULL)
{
- return get_relative_expr(entity, 2);
+ return get_relative_expr(tentity, 2);
}
else
{
@@ -4345,47 +4439,20 @@ static Expr *transform_cypher_edge(cypher_parsestate
*cpstate,
}
}
- te = findTarget(*target_list, rel->name);
- /* also search for a variable from a previous transform */
- expr = colNameToVar(pstate, rel->name, false, rel->location);
-
- if (expr != NULL)
+ /* if this vertex is referencing an existing te var, return its expr */
+ if (refs_var)
{
- return (Expr*)expr;
+ return te->expr;
}
- if (te != NULL)
+ /* if this vertex is referencing an existing col var, return its expr
*/
+ if (expr != NULL)
{
- transform_entity *entity = find_variable(cpstate, rel->name);
-
- /*
- * If the variable already exists, verify that it is for an edge.
- * You cannot have the same edge repeated in a path.
- * You cannot have an variable that is for a vertex.
- */
- if (entity != NULL)
- {
- if (entity->type == ENT_EDGE)
- {
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("duplicate edge variable '%s' within a
clause",
- rel->name),
- parser_errposition(pstate, rel->location)));
- }
- if (entity->type == ENT_VERTEX)
- {
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("variable '%s' is for a vertex",
rel->name),
- parser_errposition(pstate, rel->location)));
- }
- }
-
- return te->expr;
+ return (Expr *)expr;
}
}
+ /* if we aren't using a variable, build the edge */
if (!rel->name)
{
rel->name = get_next_default_alias(cpstate);
@@ -4417,20 +4484,20 @@ static Expr *transform_cypher_edge(cypher_parsestate
*cpstate,
if (valid_label)
{
- expr = (Expr *)make_edge_expr(cpstate, rte, rel->label);
+ expr = make_edge_expr(cpstate, rte);
}
else
{
- expr = (Expr*)makeNullConst(AGTYPEOID, -1, InvalidOid);
+ expr = (Node *)makeNullConst(AGTYPEOID, -1, InvalidOid);
}
if (rel->name)
{
- te = makeTargetEntry(expr, resno, rel->name, false);
+ te = makeTargetEntry((Expr *)expr, resno, rel->name, false);
*target_list = lappend(*target_list, te);
}
- return expr;
+ return (Expr *)expr;
}
static Expr *transform_cypher_node(cypher_parsestate *cpstate,
@@ -4438,19 +4505,80 @@ static Expr *transform_cypher_node(cypher_parsestate
*cpstate,
bool output_node, bool valid_label)
{
ParseState *pstate = (ParseState *)cpstate;
- char *schema_name;
- char *rel_name;
- RangeVar *label_range_var;
- Alias *alias;
- RangeTblEntry *rte;
- int resno;
- TargetEntry *te;
- Expr *expr;
+ char *schema_name = NULL;
+ char *rel_name = NULL;
+ RangeVar *label_range_var = NULL;
+ Alias *alias = NULL;
+ RangeTblEntry *rte = NULL;
+ int resno = -1;
+ TargetEntry *te = NULL;
+ Expr *expr = NULL;
+ transform_entity *entity = NULL;
+ cypher_node *cn = NULL;
+ bool refs_var = false;
- if (!node->label)
+ /* if we have a node name, get any potential variable references */
+ if (node->name != NULL)
{
- node->label = AG_DEFAULT_LABEL_VERTEX;
+ te = findTarget(*target_list, node->name);
+ entity = find_variable(cpstate, node->name);
+
+ /*
+ * If we have a valid entity and te for this rel name, go ahead and get
+ * the cypher relationship as we will need this for later and flag that
+ * we have a variable reference.
+ */
+ if (te != NULL && entity != NULL)
+ {
+ cn = (cypher_node *)entity->entity.node;
+ refs_var = true;
+ }
+
+ /* If the variable already exists, verify that it is for a vertex */
+ if (refs_var && entity->type != ENT_VERTEX)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("variable '%s' is for a edge", node->name),
+ parser_errposition(pstate, node->location)));
+ }
}
+
+ /*
+ * If we do not have a label for this vertex, we either need to find one
+ * from a referenced variable or we need to set it to the default label.
+ */
+ if (node->label == NULL)
+ {
+ if (refs_var)
+ {
+ /*
+ * If the referenced var has a non NULL label, copy it. This is
+ * usually the case when it uses a variable that is already
defined.
+ * Fx -
+ *
+ * MATCH (u:people)-[e:knows]->(v:people), (v)-[e]->(u) RETURN
e
+ * MATCH (u:people)-[]->()-[]->(u) RETURN u
+ *
+ * We copy it so that we know what label it is referencing.
+ */
+ if (cn->parsed_label != NULL)
+ {
+ node->parsed_label = cn->parsed_label;
+ node->label = cn->label;
+ }
+ else
+ {
+ node->label = AG_DEFAULT_LABEL_VERTEX;
+ }
+ }
+ /* otherwise, just give it the default label */
+ else
+ {
+ node->label = AG_DEFAULT_LABEL_VERTEX;
+ }
+ }
+ /* if we do have a label, is it valid */
else if (!valid_label)
{
/*
@@ -4464,18 +4592,37 @@ static Expr *transform_cypher_node(cypher_parsestate
*cpstate,
* if an all-purpose label would be useful.
*/
node->label = NULL;
+ }
+ /*
+ * If this vertex uses a variable that already exists, verify that the
label
+ * being used is of the same name.
+ */
+ if (refs_var &&
+ (cn->parsed_label != NULL || node->parsed_label != NULL) &&
+ (cn->parsed_label == NULL || node->parsed_label == NULL ||
+ (pg_strcasecmp(cn->parsed_label, node->parsed_label) != 0)))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("multiple labels for variable '%s' are not supported",
+ node->name),
+ parser_errposition(pstate, node->location)));
}
+ /* if it is not an output node, just return null */
if (!output_node)
{
return NULL;
}
+ /*
+ * Now we need to do a few checks and either return the existing var or
+ * or build a new vertex.
+ */
if (node->name != NULL)
{
- TargetEntry *te;
- Node *expr;
+ Node *expr = NULL;
/*
* If we are in a WHERE clause transform, we don't want to create new
@@ -4489,11 +4636,12 @@ static Expr *transform_cypher_node(cypher_parsestate
*cpstate,
* If expr_kind is WHERE, the expressions are in the parent's
* parent's parsestate, due to the way we transform sublinks.
*/
- transform_entity *entity = find_variable(parent_cpstate,
node->name);
+ transform_entity *tentity = NULL;
- if (entity != NULL)
+ tentity = find_variable(parent_cpstate, node->name);
+ if (tentity != NULL)
{
- return get_relative_expr(entity, 2);
+ return get_relative_expr(tentity, 2);
}
else
{
@@ -4504,49 +4652,15 @@ static Expr *transform_cypher_node(cypher_parsestate
*cpstate,
}
}
- te = findTarget(*target_list, node->name);
- /* also search for the variable from a previous transforms */
- expr = colNameToVar(pstate, node->name, false, node->location);
-
- if (te != NULL)
+ /* if this vertex is referencing an existing te var, return its expr */
+ if (refs_var)
{
- transform_entity *entity = find_variable(cpstate, node->name);
-
- /* If the variable already exists, verify that it is for a vertex
*/
- if (entity != NULL && (entity->type != ENT_VERTEX))
- {
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("variable '%s' is for a edge", node->name),
- parser_errposition(pstate, node->location)));
- }
-
- /*
- * If the variable already exists, verify that any label specified
- * is of the same name or scope. Reject those that aren't.
- */
- if (entity != NULL)
- {
- cypher_node *cnode = (cypher_node *)entity->entity.node;
-
- if (!node->label ||
- (cnode != NULL &&
- node != NULL &&
- /* allow node using a default label against resolved var */
- pg_strcasecmp(node->label, AG_DEFAULT_LABEL_VERTEX) != 0 &&
- /* allow labels with the same name */
- pg_strcasecmp(cnode->label, node->label) != 0))
- {
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("multiple labels for variable '%s' are not
supported", node->name),
- parser_errposition(pstate, node->location)));
- }
- }
-
return te->expr;
}
- else if (expr != NULL)
+
+ /* if this vertex is referencing an existing col var, return its expr
*/
+ expr = colNameToVar(pstate, node->name, false, node->location);
+ if (expr != NULL)
{
return (Expr*)expr;
}
@@ -4556,6 +4670,7 @@ static Expr *transform_cypher_node(cypher_parsestate
*cpstate,
node->name = get_next_default_alias(cpstate);
}
+ /* now build a new vertex */
schema_name = get_graph_namespace_name(cpstate->graph_name);
if (valid_label)
@@ -4582,7 +4697,7 @@ static Expr *transform_cypher_node(cypher_parsestate
*cpstate,
if (valid_label)
{
- expr = (Expr *)make_vertex_expr(cpstate, rte, node->label);
+ expr = (Expr *)make_vertex_expr(cpstate, rte);
}
else
{
@@ -4596,8 +4711,7 @@ static Expr *transform_cypher_node(cypher_parsestate
*cpstate,
return expr;
}
-static Node *make_edge_expr(cypher_parsestate *cpstate, RangeTblEntry *rte,
- char *label)
+static Node *make_edge_expr(cypher_parsestate *cpstate, RangeTblEntry *rte)
{
ParseState *pstate = (ParseState *)cpstate;
Oid label_name_func_oid;
@@ -4645,8 +4759,7 @@ static Node *make_edge_expr(cypher_parsestate *cpstate,
RangeTblEntry *rte,
return (Node *)func_expr;
}
-static Node *make_vertex_expr(cypher_parsestate *cpstate, RangeTblEntry *rte,
- char *label)
+static Node *make_vertex_expr(cypher_parsestate *cpstate, RangeTblEntry *rte)
{
ParseState *pstate = (ParseState *)cpstate;
Oid label_name_func_oid;
diff --git a/src/backend/parser/cypher_gram.y b/src/backend/parser/cypher_gram.y
index 5f8dc2d8..4fb599a7 100644
--- a/src/backend/parser/cypher_gram.y
+++ b/src/backend/parser/cypher_gram.y
@@ -1180,6 +1180,7 @@ path_node:
n = make_ag_node(cypher_node);
n->name = $2;
n->label = $3;
+ n->parsed_label = $3;
n->props = $4;
n->location = @1;
@@ -1225,6 +1226,7 @@ path_relationship_body:
n = make_ag_node(cypher_relationship);
n->name = $2;
n->label = $3;
+ n->parsed_label = $3;
n->varlen = $4;
n->props = $5;
@@ -1238,6 +1240,7 @@ path_relationship_body:
n = make_ag_node(cypher_relationship);
n->name = NULL;
n->label = NULL;
+ n->parsed_label = NULL;
n->varlen = NULL;
n->props = NULL;
diff --git a/src/include/nodes/cypher_nodes.h b/src/include/nodes/cypher_nodes.h
index afe3127e..d6d8c02d 100644
--- a/src/include/nodes/cypher_nodes.h
+++ b/src/include/nodes/cypher_nodes.h
@@ -142,6 +142,7 @@ typedef struct cypher_node
ExtensibleNode extensible;
char *name;
char *label;
+ char *parsed_label;
Node *props; // map or parameter
int location;
} cypher_node;
@@ -159,6 +160,7 @@ typedef struct cypher_relationship
ExtensibleNode extensible;
char *name;
char *label;
+ char *parsed_label;
Node *props; // map or parameter
Node *varlen; // variable length relationships (A_Indices)
cypher_rel_dir dir;