This is an automated email from the ASF dual-hosted git repository. zainabsaad pushed a commit to branch fix/issue_1513_PG16 in repository https://gitbox.apache.org/repos/asf/age.git
commit c3a65b79613a1e549cf83e20039ff95866cc1e00 Author: Zainab Saad <[email protected]> AuthorDate: Wed Feb 7 20:30:41 2024 +0500 Fix apache#1513 - Invalid variable reuse in CREATE and MERGE clause 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 212cd26e..c164e194 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, @@ -5336,7 +5336,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; @@ -5361,9 +5361,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) { @@ -5418,6 +5420,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; @@ -5489,7 +5492,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), @@ -5602,7 +5605,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; @@ -5636,7 +5639,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), @@ -5649,6 +5652,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 @@ -6682,7 +6692,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; @@ -6695,6 +6705,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) @@ -6716,7 +6727,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) @@ -6772,6 +6784,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 @@ -6807,7 +6820,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), @@ -6906,8 +6919,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; @@ -6918,19 +6932,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; }
