This is an automated email from the ASF dual-hosted git repository.

jgemignani pushed a commit to branch PG15
in repository https://gitbox.apache.org/repos/asf/age.git


The following commit(s) were added to refs/heads/PG15 by this push:
     new ce6f1b3c Fix apache#1513 - Invalid variable reuse in CREATE and MERGE 
clause (#1566)
ce6f1b3c is described below

commit ce6f1b3c1123b20505698b4de73803830e2eb4b8
Author: Zainab Saad <[email protected]>
AuthorDate: Wed Feb 7 23:54:57 2024 +0500

    Fix apache#1513 - Invalid variable reuse in CREATE and MERGE clause (#1566)
    
    Allow the reuse of a previously declared vertex variable only if the 
succeeding
    CREATE/MERGE vertex has associated edges
    i.e CREATE (n) CREATE (n)             -- invalid
        CREATE (n) CREATE (n)-[:edge]->() -- valid
    
    Fixed another invalid variable reuse where in a CREATE path, edge variable
    could be duplicated which resulted in ambiguous reference error
    
    Added regression tests
---
 regress/expected/cypher_create.out | 120 ++++++++++++++++++++++++++++++++++++-
 regress/expected/cypher_merge.out  |  86 +++++++++++++++++++++++++-
 regress/sql/cypher_create.sql      |  72 ++++++++++++++++++++++
 regress/sql/cypher_merge.sql       |  52 ++++++++++++++++
 src/backend/parser/cypher_clause.c |  66 ++++++++++++++------
 5 files changed, 373 insertions(+), 23 deletions(-)

diff --git a/regress/expected/cypher_create.out 
b/regress/expected/cypher_create.out
index 91b95d39..2388af8a 100644
--- a/regress/expected/cypher_create.out
+++ b/regress/expected/cypher_create.out
@@ -714,7 +714,9 @@ LINE 2:  CREATE p=(p)
 SELECT * FROM cypher('cypher_create', $$
        CREATE p=() CREATE (p)
 $$) as (a agtype);
-ERROR:  agtype must resolve to a vertex
+ERROR:  variable p already exists
+LINE 2:  CREATE p=() CREATE (p)
+                             ^
 SELECT * FROM cypher('cypher_create', $$
        CREATE p=(a)-[p:b]->(a)
 $$) as (a agtype);
@@ -748,7 +750,7 @@ LINE 2:  MATCH (p) CREATE (a)-[p:b]->(a)
 SELECT * FROM cypher('cypher_create', $$
        CREATE (a)-[e:new]->(p)-[e]->(a)
 $$) as (a agtype);
-ERROR:  relationships must be specify a label in CREATE.
+ERROR:  variable e already exists
 LINE 2:  CREATE (a)-[e:new]->(p)-[e]->(a)
                                  ^
 SELECT * FROM cypher('cypher_create', $$
@@ -793,13 +795,124 @@ $$) as (a agtype);
  {"id": 5910974510923777, "label": "CrEaTe", "properties": {}}::vertex
 (1 row)
 
+--
+-- the following tests should fail due to invalid variable reuse (issue#1513)
+--
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n) CREATE (n) RETURN n
+$$) as (n agtype);
+ERROR:  variable n already exists
+LINE 2:   CREATE (n) CREATE (n) RETURN n
+                             ^
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n), (n) RETURN n
+$$) as (n agtype);
+ERROR:  variable n already exists
+LINE 2:   CREATE (n), (n) RETURN n
+                       ^
+SELECT * FROM cypher('cypher_create', $$
+  MATCH (n) CREATE (n) RETURN n
+$$) as (n agtype);
+ERROR:  variable n already exists
+LINE 2:   MATCH (n) CREATE (n) RETURN n
+                            ^
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n), (n)-[:edge]->(n), (n) RETURN n
+$$) as (n agtype);
+ERROR:  variable n already exists
+LINE 2:   CREATE (n), (n)-[:edge]->(n), (n) RETURN n
+                                         ^
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n)-[e:edge]->(m) CREATE (n), (m) RETURN n
+$$) as (n agtype);
+ERROR:  variable n already exists
+LINE 2:   CREATE (n)-[e:edge]->(m) CREATE (n), (m) RETURN n
+                                           ^
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n)-[e:edge]->(m) CREATE (), (m) RETURN m
+$$) as (m agtype);
+ERROR:  variable m already exists
+LINE 2:   CREATE (n)-[e:edge]->(m) CREATE (), (m) RETURN m
+                                               ^
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n)-[e:edge]->(m) CREATE (), (e) RETURN e
+$$) as (e agtype);
+ERROR:  variable e already exists
+LINE 2:   CREATE (n)-[e:edge]->(m) CREATE (), (e) RETURN e
+                                               ^
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n)-[e:edge]->(m) CREATE (n)-[e:edge]->(m) RETURN e
+$$) as (e agtype);
+ERROR:  variable e already exists
+LINE 2:   CREATE (n)-[e:edge]->(m) CREATE (n)-[e:edge]->(m) RETURN e
+                                              ^
+SELECT * FROM cypher('cypher_create', $$
+  WITH {id: 281474976710657, label: "", properties: {}}::vertex AS n CREATE 
(n) RETURN n
+$$) as (n agtype);
+ERROR:  variable n already exists
+LINE 2: ..., label: "", properties: {}}::vertex AS n CREATE (n) RETURN ...
+                                                             ^
+SELECT * FROM cypher('cypher_create', $$
+       CREATE (n)-[e:edge]->(n)-[e:edge]->(n) RETURN e
+$$) as (e agtype);
+ERROR:  variable e already exists
+LINE 2:  CREATE (n)-[e:edge]->(n)-[e:edge]->(n) RETURN e
+                                  ^
+SELECT * FROM cypher('cypher_create', $$
+       CREATE ()-[e:edge]->(), (n)-[e:edge]->(n)-[e:edge]->(n) RETURN e
+$$) as (e agtype);
+ERROR:  variable e already exists
+LINE 2:  CREATE ()-[e:edge]->(), (n)-[e:edge]->(n)-[e:edge]->(n) RET...
+                                     ^
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n)-[e:edge]->(m) CREATE (e)-[:edge]->() RETURN e
+$$) as (e agtype);
+ERROR:  variable e already exists
+LINE 2:   CREATE (n)-[e:edge]->(m) CREATE (e)-[:edge]->() RETURN e
+                                           ^
+SELECT * FROM cypher('cypher_create', $$
+       WITH {id: 1407374883553281, label: "edge", end_id: 281474976710658, 
start_id: 281474976710657, properties: {}}::edge AS e CREATE ()-[e:edge]->() 
RETURN e
+$$) as (e agtype);
+ERROR:  variable e already exists
+LINE 2: ...74976710657, properties: {}}::edge AS e CREATE ()-[e:edge]->...
+                                                             ^
+SELECT * FROM cypher('cypher_create', $$
+       CREATE (n) WITH n AS r CREATE (r) RETURN r
+$$) as (r agtype);
+ERROR:  variable r already exists
+LINE 2:  CREATE (n) WITH n AS r CREATE (r) RETURN r
+                                        ^
+-- valid variable reuse
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n)-[e1:edge]->(m) CREATE (n)-[e2:edge]->(m)
+$$) as (n agtype);
+ n 
+---
+(0 rows)
+
+SELECT * FROM cypher('cypher_create', $$
+       CREATE (n) WITH n AS r CREATE (r)-[e:edge]->() RETURN r
+$$) as (r agtype);
+                               r                                
+----------------------------------------------------------------
+ {"id": 281474976710685, "label": "", "properties": {}}::vertex
+(1 row)
+
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n), (m) WITH n AS r CREATE (m) RETURN m
+$$) as (m agtype);
+                               m                                
+----------------------------------------------------------------
+ {"id": 281474976710689, "label": "", "properties": {}}::vertex
+(1 row)
+
 --
 -- Clean up
 --
 DROP TABLE simple_path;
 DROP FUNCTION create_test;
 SELECT drop_graph('cypher_create', true);
-NOTICE:  drop cascades to 19 other objects
+NOTICE:  drop cascades to 20 other objects
 DETAIL:  drop cascades to table cypher_create._ag_label_vertex
 drop cascades to table cypher_create._ag_label_edge
 drop cascades to table cypher_create.v
@@ -819,6 +932,7 @@ drop cascades to table cypher_create.n1
 drop cascades to table cypher_create."CREATE"
 drop cascades to table cypher_create."create"
 drop cascades to table cypher_create."CrEaTe"
+drop cascades to table cypher_create.edge
 NOTICE:  graph "cypher_create" has been dropped
  drop_graph 
 ------------
diff --git a/regress/expected/cypher_merge.out 
b/regress/expected/cypher_merge.out
index 7427c8e7..39690e7c 100644
--- a/regress/expected/cypher_merge.out
+++ b/regress/expected/cypher_merge.out
@@ -817,7 +817,9 @@ SELECT * FROM cypher('cypher_merge', $$CREATE (n)$$) AS (a 
agtype);
 
 --test query
 SELECT * FROM cypher('cypher_merge', $$MATCH (n) OPTIONAL MATCH (n)-[:e]->(m) 
MERGE (m)$$) AS (a agtype);
-ERROR:  Existing variable m cannot be NULL in MERGE clause
+ERROR:  variable m already exists
+LINE 1: ..., $$MATCH (n) OPTIONAL MATCH (n)-[:e]->(m) MERGE (m)$$) AS (...
+                                                             ^
 -- validate only 1 vertex exits
 SELECT * FROM cypher('cypher_merge', $$MATCH (n) RETURN n$$) AS (a agtype);
                                a                                
@@ -1182,6 +1184,85 @@ NOTICE:  graph "issue_1219" has been dropped
  
 (1 row)
 
+--
+-- the following tests should fail due to invalid variable reuse (issue#1513)
+--
+SELECT * FROM cypher('cypher_merge', $$
+  MERGE (n) MERGE (n) RETURN n
+$$) as (a agtype);
+ERROR:  variable n already exists
+LINE 2:   MERGE (n) MERGE (n) RETURN n
+                           ^
+SELECT * FROM cypher('cypher_merge', $$
+  MATCH (n) MERGE (n) RETURN n
+$$) as (a agtype);
+ERROR:  variable n already exists
+LINE 2:   MATCH (n) MERGE (n) RETURN n
+                           ^
+SELECT * FROM cypher('cypher_merge', $$
+  CREATE (n) MERGE (n) RETURN n
+$$) as (a agtype);
+ERROR:  variable n already exists
+LINE 2:   CREATE (n) MERGE (n) RETURN n
+                            ^
+SELECT * FROM cypher('cypher_merge', $$
+  MATCH (n) WITH n AS r MERGE (r) RETURN r
+$$) as (a agtype);
+ERROR:  variable r already exists
+LINE 2:   MATCH (n) WITH n AS r MERGE (r) RETURN r
+                                       ^
+SELECT * FROM cypher('cypher_merge', $$
+  WITH {id: 281474976710657, label: "", properties: {}}::vertex AS n MERGE (n) 
RETURN n
+$$) as (a agtype);
+ERROR:  variable n already exists
+LINE 2: ...7, label: "", properties: {}}::vertex AS n MERGE (n) RETURN ...
+                                                             ^
+SELECT * FROM cypher('cypher_merge', $$
+       MERGE (n)-[e:edge]->(n)-[e1:edge]->(n) MERGE(n) RETURN e
+$$) as (a agtype);
+ERROR:  variable n already exists
+LINE 2:  MERGE (n)-[e:edge]->(n)-[e1:edge]->(n) MERGE(n) RETURN e
+                                                      ^
+SELECT * FROM cypher('cypher_merge', $$
+  MERGE (n)-[e:edge]->(m) MERGE (e)-[:edge]->() RETURN e
+$$) as (a agtype);
+ERROR:  variable 'e' is for an edge
+LINE 2:   MERGE (n)-[e:edge]->(m) MERGE (e)-[:edge]->() RETURN e
+                                         ^
+SELECT * FROM cypher('cypher_merge', $$
+       WITH {id: 1407374883553281, label: "edge", end_id: 281474976710658, 
start_id: 281474976710657, properties: {}}::edge AS e MERGE ()-[e:edge]->() 
RETURN e
+$$) as (a agtype);
+ERROR:  variable e already exists
+LINE 2: ...474976710657, properties: {}}::edge AS e MERGE ()-[e:edge]->...
+                                                             ^
+SELECT * FROM cypher('cypher_merge', $$
+  MATCH (n) WITH n AS r MERGE (r) RETURN r
+$$) as (a agtype);
+ERROR:  variable r already exists
+LINE 2:   MATCH (n) WITH n AS r MERGE (r) RETURN r
+                                       ^
+-- valid variable reuse
+SELECT * FROM cypher('cypher_merge', $$
+  MERGE (n)-[e1:edge]->(m) MERGE (n)-[e2:edge]->()
+$$) as (n agtype);
+ n 
+---
+(0 rows)
+
+SELECT * FROM cypher('cypher_merge', $$
+  MERGE (n) WITH n AS r MERGE (r)-[e:edge]->()
+$$) as (a agtype);
+ a 
+---
+(0 rows)
+
+SELECT * FROM cypher('cypher_merge', $$
+  CREATE (n), (m) WITH n AS r MERGE (m)
+$$) as (a agtype);
+ a 
+---
+(0 rows)
+
 --clean up
 SELECT * FROM cypher('cypher_merge', $$MATCH (n) DETACH DELETE n $$) AS (a 
agtype);
  a 
@@ -1192,7 +1273,7 @@ SELECT * FROM cypher('cypher_merge', $$MATCH (n) DETACH 
DELETE n $$) AS (a agtyp
  * Clean up graph
  */
 SELECT drop_graph('cypher_merge', true);
-NOTICE:  drop cascades to 18 other objects
+NOTICE:  drop cascades to 19 other objects
 DETAIL:  drop cascades to table cypher_merge._ag_label_vertex
 drop cascades to table cypher_merge._ag_label_edge
 drop cascades to table cypher_merge.e
@@ -1211,6 +1292,7 @@ drop cascades to table cypher_merge."P"
 drop cascades to table cypher_merge."Q"
 drop cascades to table cypher_merge."R"
 drop cascades to table cypher_merge."E1"
+drop cascades to table cypher_merge.edge
 NOTICE:  graph "cypher_merge" has been dropped
  drop_graph 
 ------------
diff --git a/regress/sql/cypher_create.sql b/regress/sql/cypher_create.sql
index 8c9ac899..0093dc44 100644
--- a/regress/sql/cypher_create.sql
+++ b/regress/sql/cypher_create.sql
@@ -403,6 +403,78 @@ SELECT * FROM cypher('cypher_create', $$
        RETURN a
 $$) as (a agtype);
 
+--
+-- the following tests should fail due to invalid variable reuse (issue#1513)
+--
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n) CREATE (n) RETURN n
+$$) as (n agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n), (n) RETURN n
+$$) as (n agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+  MATCH (n) CREATE (n) RETURN n
+$$) as (n agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n), (n)-[:edge]->(n), (n) RETURN n
+$$) as (n agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n)-[e:edge]->(m) CREATE (n), (m) RETURN n
+$$) as (n agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n)-[e:edge]->(m) CREATE (), (m) RETURN m
+$$) as (m agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n)-[e:edge]->(m) CREATE (), (e) RETURN e
+$$) as (e agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n)-[e:edge]->(m) CREATE (n)-[e:edge]->(m) RETURN e
+$$) as (e agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+  WITH {id: 281474976710657, label: "", properties: {}}::vertex AS n CREATE 
(n) RETURN n
+$$) as (n agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+       CREATE (n)-[e:edge]->(n)-[e:edge]->(n) RETURN e
+$$) as (e agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+       CREATE ()-[e:edge]->(), (n)-[e:edge]->(n)-[e:edge]->(n) RETURN e
+$$) as (e agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n)-[e:edge]->(m) CREATE (e)-[:edge]->() RETURN e
+$$) as (e agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+       WITH {id: 1407374883553281, label: "edge", end_id: 281474976710658, 
start_id: 281474976710657, properties: {}}::edge AS e CREATE ()-[e:edge]->() 
RETURN e
+$$) as (e agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+       CREATE (n) WITH n AS r CREATE (r) RETURN r
+$$) as (r agtype);
+
+-- valid variable reuse
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n)-[e1:edge]->(m) CREATE (n)-[e2:edge]->(m)
+$$) as (n agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+       CREATE (n) WITH n AS r CREATE (r)-[e:edge]->() RETURN r
+$$) as (r agtype);
+
+SELECT * FROM cypher('cypher_create', $$
+  CREATE (n), (m) WITH n AS r CREATE (m) RETURN m
+$$) as (m agtype);
+
 --
 -- Clean up
 --
diff --git a/regress/sql/cypher_merge.sql b/regress/sql/cypher_merge.sql
index 81d965a2..f6aceea8 100644
--- a/regress/sql/cypher_merge.sql
+++ b/regress/sql/cypher_merge.sql
@@ -554,6 +554,58 @@ SELECT * FROM cypher('issue_1219', $$ MATCH (x) RETURN x 
$$) as (result agtype);
 SELECT * FROM cypher('issue_1219', $$ MATCH ()-[e]->() RETURN e $$) as (result 
agtype);
 SELECT drop_graph('issue_1219', true);
 
+--
+-- the following tests should fail due to invalid variable reuse (issue#1513)
+--
+SELECT * FROM cypher('cypher_merge', $$
+  MERGE (n) MERGE (n) RETURN n
+$$) as (a agtype);
+
+SELECT * FROM cypher('cypher_merge', $$
+  MATCH (n) MERGE (n) RETURN n
+$$) as (a agtype);
+
+SELECT * FROM cypher('cypher_merge', $$
+  CREATE (n) MERGE (n) RETURN n
+$$) as (a agtype);
+
+SELECT * FROM cypher('cypher_merge', $$
+  MATCH (n) WITH n AS r MERGE (r) RETURN r
+$$) as (a agtype);
+
+SELECT * FROM cypher('cypher_merge', $$
+  WITH {id: 281474976710657, label: "", properties: {}}::vertex AS n MERGE (n) 
RETURN n
+$$) as (a agtype);
+
+SELECT * FROM cypher('cypher_merge', $$
+       MERGE (n)-[e:edge]->(n)-[e1:edge]->(n) MERGE(n) RETURN e
+$$) as (a agtype);
+
+SELECT * FROM cypher('cypher_merge', $$
+  MERGE (n)-[e:edge]->(m) MERGE (e)-[:edge]->() RETURN e
+$$) as (a agtype);
+
+SELECT * FROM cypher('cypher_merge', $$
+       WITH {id: 1407374883553281, label: "edge", end_id: 281474976710658, 
start_id: 281474976710657, properties: {}}::edge AS e MERGE ()-[e:edge]->() 
RETURN e
+$$) as (a agtype);
+
+SELECT * FROM cypher('cypher_merge', $$
+  MATCH (n) WITH n AS r MERGE (r) RETURN r
+$$) as (a agtype);
+
+-- valid variable reuse
+SELECT * FROM cypher('cypher_merge', $$
+  MERGE (n)-[e1:edge]->(m) MERGE (n)-[e2:edge]->()
+$$) as (n agtype);
+
+SELECT * FROM cypher('cypher_merge', $$
+  MERGE (n) WITH n AS r MERGE (r)-[e:edge]->()
+$$) as (a agtype);
+
+SELECT * FROM cypher('cypher_merge', $$
+  CREATE (n), (m) WITH n AS r MERGE (m)
+$$) as (a agtype);
+
 --clean up
 SELECT * FROM cypher('cypher_merge', $$MATCH (n) DETACH DELETE n $$) AS (a 
agtype);
 
diff --git a/src/backend/parser/cypher_clause.c 
b/src/backend/parser/cypher_clause.c
index bf83baf0..628900b7 100644
--- a/src/backend/parser/cypher_clause.c
+++ b/src/backend/parser/cypher_clause.c
@@ -181,7 +181,7 @@ transform_cypher_create_path(cypher_parsestate *cpstate, 
List **target_list,
                              cypher_path *cp);
 static cypher_target_node *
 transform_create_cypher_node(cypher_parsestate *cpstate, List **target_list,
-                             cypher_node *node);
+                             cypher_node *node, bool has_edge);
 static cypher_target_node *
 transform_create_cypher_new_node(cypher_parsestate *cpstate,
                                  List **target_list, cypher_node *node);
@@ -255,7 +255,7 @@ transform_merge_cypher_edge(cypher_parsestate *cpstate, 
List **target_list,
                             cypher_relationship *edge);
 static cypher_target_node *
 transform_merge_cypher_node(cypher_parsestate *cpstate, List **target_list,
-                            cypher_node *node);
+                            cypher_node *node, bool has_edge);
 static Node *transform_clause_for_join(cypher_parsestate *cpstate,
                                        cypher_clause *clause,
                                        RangeTblEntry **rte,
@@ -5307,7 +5307,7 @@ transform_cypher_create_path(cypher_parsestate *cpstate, 
List **target_list,
                              cypher_path *path)
 {
     ParseState *pstate = (ParseState *)cpstate;
-    ListCell *lc;
+    ListCell *lc, *prev_node = NULL;
     List *transformed_path = NIL;
     cypher_create_path *ccp = make_ag_node(cypher_create_path);
     bool in_path = path->var_name != NULL;
@@ -5332,9 +5332,11 @@ transform_cypher_create_path(cypher_parsestate *cpstate, 
List **target_list,
         {
             cypher_node *node = lfirst(lc);
             transform_entity *entity;
+            ListCell *next_node = lnext(path->path, lc);
 
             cypher_target_node *rel =
-                transform_create_cypher_node(cpstate, target_list, node);
+                transform_create_cypher_node(cpstate, target_list, node,
+                                             (next_node || prev_node));
 
             if (in_path)
             {
@@ -5389,6 +5391,7 @@ transform_cypher_create_path(cypher_parsestate *cpstate, 
List **target_list,
             ereport(ERROR,
                     (errmsg_internal("unrecognized node in create pattern")));
         }
+        prev_node = lc;
     }
 
     ccp->target_nodes = transformed_path;
@@ -5460,7 +5463,7 @@ transform_create_cypher_edge(cypher_parsestate *cpstate, 
List **target_list,
 
         entity = find_variable(cpstate, edge->name);
 
-        if ((entity && entity->type != ENT_EDGE) || variable_exists(cpstate, 
edge->name))
+        if (entity || variable_exists(cpstate, edge->name))
         {
                 ereport(ERROR,
                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -5573,7 +5576,7 @@ static bool variable_exists(cypher_parsestate *cpstate, 
char *name)
 // transform nodes, check to see if the variable name already exists.
 static cypher_target_node *
 transform_create_cypher_node(cypher_parsestate *cpstate, List **target_list,
-                             cypher_node *node)
+                             cypher_node *node, bool has_edge)
 {
     ParseState *pstate = (ParseState *)cpstate;
 
@@ -5607,7 +5610,7 @@ transform_create_cypher_node(cypher_parsestate *cpstate, 
List **target_list,
          */
         if (entity && te)
         {
-            if (entity->type != ENT_VERTEX)
+            if (entity->type != ENT_VERTEX || !has_edge)
             {
                 ereport(ERROR,
                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -5620,6 +5623,13 @@ transform_create_cypher_node(cypher_parsestate *cpstate, 
List **target_list,
         }
         else if (te)
         {
+            if (!has_edge)
+            {
+                ereport(ERROR,
+                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                         errmsg("variable %s already exists", node->name),
+                         parser_errposition(pstate, node->location)));
+            }
             /*
              * Here we are not sure if the te is a vertex, path or something
              * else. So we will let it pass and the execution stage will catch
@@ -6645,7 +6655,7 @@ transform_cypher_merge_path(cypher_parsestate *cpstate, 
List **target_list,
                             cypher_path *path)
 {
     ParseState *pstate = (ParseState *)cpstate;
-    ListCell *lc;
+    ListCell *lc, *prev_node = NULL;
     List *transformed_path = NIL;
     cypher_create_path *ccp = make_ag_node(cypher_create_path);
     bool in_path = path->var_name != NULL;
@@ -6658,6 +6668,7 @@ transform_cypher_merge_path(cypher_parsestate *cpstate, 
List **target_list,
         {
             cypher_node *node = lfirst(lc);
             cypher_target_node *rel = NULL;
+            ListCell *next_node = lnext(path->path, lc);
 
             if (path->var_name != NULL && node->name != NULL &&
                 strcmp(path->var_name, node->name) == 0)
@@ -6679,7 +6690,8 @@ transform_cypher_merge_path(cypher_parsestate *cpstate, 
List **target_list,
             /* if there wasn't a transformed variable, transform the node */
             if (rel == NULL)
             {
-                rel = transform_merge_cypher_node(cpstate, target_list, node);
+                rel = transform_merge_cypher_node(cpstate, target_list, node,
+                                                  (next_node || prev_node));
             }
 
             if (in_path)
@@ -6735,6 +6747,7 @@ transform_cypher_merge_path(cypher_parsestate *cpstate, 
List **target_list,
             ereport(ERROR,
                     (errmsg_internal("unrecognized node in create pattern")));
         }
+        prev_node = lc;
     }
 
     // store the path's variable name
@@ -6770,7 +6783,7 @@ transform_merge_cypher_edge(cypher_parsestate *cpstate, 
List **target_list,
                                                          ENT_EDGE);
 
         // We found a variable with this variable name, throw an error.
-        if (entity != NULL)
+        if (entity || variable_exists(cpstate, edge->name))
         {
             ereport(ERROR,
                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -6871,8 +6884,9 @@ transform_merge_cypher_edge(cypher_parsestate *cpstate, 
List **target_list,
  */
 static cypher_target_node *
 transform_merge_cypher_node(cypher_parsestate *cpstate, List **target_list,
-                            cypher_node *node)
+                            cypher_node *node, bool has_edge)
 {
+    ParseState *pstate = (ParseState *)cpstate;
     cypher_target_node *rel = make_ag_node(cypher_target_node);
     Relation label_relation;
     RangeVar *rv;
@@ -6883,19 +6897,35 @@ transform_merge_cypher_node(cypher_parsestate *cpstate, 
List **target_list,
     {
         transform_entity *entity = find_transform_entity(cpstate, node->name,
                                                          ENT_VERTEX);
+        bool var_exists = variable_exists(cpstate, node->name);
         /*
          *  the vertex was previously declared, we do not need to do any setup
          *  to create the node.
          */
-        if (entity != NULL)
+        if (entity && var_exists)
         {
-                rel->type = LABEL_KIND_VERTEX;
-                rel->tuple_position = InvalidAttrNumber;
-                rel->variable_name = node->name;
-                rel->resultRelInfo = NULL;
+            if (!has_edge)
+            {
+                ereport(ERROR,
+                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                         errmsg("variable %s already exists", node->name),
+                         parser_errposition(pstate, node->location)));
+            }
+
+            rel->type = LABEL_KIND_VERTEX;
+            rel->tuple_position = InvalidAttrNumber;
+            rel->variable_name = node->name;
+            rel->resultRelInfo = NULL;
 
-                rel->flags |= CYPHER_TARGET_NODE_MERGE_EXISTS;
-                return rel;
+            rel->flags |= CYPHER_TARGET_NODE_MERGE_EXISTS;
+            return rel;
+        }
+        else if (var_exists && !has_edge)
+        {
+            ereport(ERROR,
+                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                         errmsg("variable %s already exists", node->name),
+                         parser_errposition(pstate, node->location)));
         }
         rel->flags |= CYPHER_TARGET_NODE_IS_VAR;
     }

Reply via email to