diff --git a/regress/expected/cypher_match.out b/regress/expected/cypher_match.out index aaf462272..a207cabff 100644 --- a/regress/expected/cypher_match.out +++ b/regress/expected/cypher_match.out @@ -766,7 +766,7 @@ 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 +ERROR: variable 'r0' is for an edge LINE 2: MATCH ()-[r0]->() MATCH ()-[]->(r0) RETURN r0 ^ SELECT * FROM cypher('cypher_match', $$ @@ -2052,6 +2052,58 @@ SELECT * FROM cypher('cypher_match', $$ MATCH p=(a)-[b:knows]->()-[b]->(a) RETUR ERROR: duplicate edge variable 'b' within a clause LINE 1: ...pher('cypher_match', $$ MATCH p=(a)-[b:knows]->()-[b]->(a) R... ^ +SELECT * FROM cypher('cypher_match', $$ MATCH p=(p) RETURN p $$)as (p agtype); +ERROR: variable "p" is for a path +LINE 1: SELECT * FROM cypher('cypher_match', $$ MATCH p=(p) RETURN p... + ^ +SELECT * FROM cypher('cypher_match', $$ MATCH p=(p)-[]->() RETURN p $$)as (p agtype); +ERROR: variable "p" is for a path +LINE 1: SELECT * FROM cypher('cypher_match', $$ MATCH p=(p)-[]->() R... + ^ +SELECT * FROM cypher('cypher_match', $$ MATCH p=()-[p]->() RETURN p $$)as (p agtype); +ERROR: variable "p" is for a path +LINE 1: ...ELECT * FROM cypher('cypher_match', $$ MATCH p=()-[p]->() RE... + ^ +SELECT * FROM cypher('cypher_match', $$ MATCH p=() MATCH (p) RETURN p $$)as (p agtype); +ERROR: variable 'p' already exists +LINE 1: ... FROM cypher('cypher_match', $$ MATCH p=() MATCH (p) RETURN ... + ^ +SELECT * FROM cypher('cypher_match', $$ MATCH p=() MATCH (p)-[]->() RETURN p $$)as (p agtype); +ERROR: variable 'p' already exists +LINE 1: ... FROM cypher('cypher_match', $$ MATCH p=() MATCH (p)-[]->() ... + ^ +SELECT * FROM cypher('cypher_match', $$ MATCH p=() MATCH ()-[p]->() RETURN p $$)as (p agtype); +ERROR: variable 'p' already exists +LINE 1: ...ROM cypher('cypher_match', $$ MATCH p=() MATCH ()-[p]->() RE... + ^ +SELECT * FROM cypher('cypher_match', $$ MATCH (p) MATCH p=() RETURN p $$)as (p agtype); +ERROR: variable "p" already exists +LINE 1: ... * FROM cypher('cypher_match', $$ MATCH (p) MATCH p=() RETUR... + ^ +SELECT * FROM cypher('cypher_match', $$ MATCH ()-[p]->() MATCH p=() RETURN p $$)as (p agtype); +ERROR: variable "p" already exists +LINE 1: ... cypher('cypher_match', $$ MATCH ()-[p]->() MATCH p=() RETUR... + ^ +SELECT * FROM cypher('cypher_match', $$ MATCH ()-[p *]-()-[p]-() RETURN 0 $$)as (p agtype); +ERROR: variable 'p' is for a VLE edge +LINE 1: ... FROM cypher('cypher_match', $$ MATCH ()-[p *]-()-[p]-() RET... + ^ +SELECT * FROM cypher('cypher_match', $$ CREATE (p) WITH p MATCH p=() RETURN p $$)as (p agtype); +ERROR: variable "p" already exists +LINE 1: ...cypher('cypher_match', $$ CREATE (p) WITH p MATCH p=() RETUR... + ^ +SELECT * FROM cypher('cypher_match', $$ CREATE p=() WITH p MATCH (p) RETURN p $$)as (p agtype); +ERROR: variable 'p' already exists +LINE 1: ...pher('cypher_match', $$ CREATE p=() WITH p MATCH (p) RETURN ... + ^ +SELECT * FROM cypher('cypher_match', $$ CREATE ()-[p:knows]->() WITH p MATCH p=() RETURN p $$)as (p agtype); +ERROR: variable "p" already exists +LINE 1: ...r_match', $$ CREATE ()-[p:knows]->() WITH p MATCH p=() RETUR... + ^ +SELECT * FROM cypher('cypher_match', $$ CREATE p=() WITH p MATCH ()-[p]->() RETURN p $$)as (p agtype); +ERROR: variable 'p' already exists +LINE 1: ...er('cypher_match', $$ CREATE p=() WITH p MATCH ()-[p]->() RE... + ^ -- -- Default alias check (issue #883) -- diff --git a/regress/expected/cypher_vle.out b/regress/expected/cypher_vle.out index 5f8f922c2..e153ce972 100644 --- a/regress/expected/cypher_vle.out +++ b/regress/expected/cypher_vle.out @@ -761,6 +761,59 @@ NOTICE: graph "mygraph" has been dropped (1 row) +-- invalid reuse of VLE +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p]-()-[p *]-() RETURN p $$)as (p agtype); +ERROR: variable 'p' is for an edge +LINE 1: ...CT * FROM cypher('cypher_vle', $$ MATCH ()-[p]-()-[p *]-() R... + ^ +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-()-[p]-() RETURN p $$)as (p agtype); +ERROR: variable 'p' is for a VLE edge +LINE 1: ... * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-()-[p]-() RET... + ^ +SELECT * FROM cypher('cypher_vle', $$ MATCH (p)-[p *]-() RETURN p $$)as (p agtype); +ERROR: variable 'p' is for a vertex +LINE 1: SELECT * FROM cypher('cypher_vle', $$ MATCH (p)-[p *]-() RET... + ^ +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-(p) RETURN p $$)as (p agtype); +ERROR: variable 'p' is for a VLE edge +LINE 1: ...CT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-(p) RETURN ... + ^ +SELECT * FROM cypher('cypher_vle', $$ MATCH p=()-[p *]-() RETURN p $$)as (p agtype); +ERROR: variable "p" is for a path +LINE 1: SELECT * FROM cypher('cypher_vle', $$ MATCH p=()-[p *]-() RE... + ^ +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-()-[p *]-() RETURN p $$)as (p agtype); +ERROR: duplicate variable 'p' +LINE 1: ... * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-()-[p *]-() R... + ^ +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p]-() MATCH ()-[p *]-() RETURN p $$)as (p agtype); +ERROR: variable 'p' is for an edge +LINE 1: ... cypher('cypher_vle', $$ MATCH ()-[p]-() MATCH ()-[p *]-() R... + ^ +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-() MATCH ()-[p]-() RETURN p $$)as (p agtype); +ERROR: variable 'p' is for a VLE edge +LINE 1: ...ypher('cypher_vle', $$ MATCH ()-[p *]-() MATCH ()-[p]-() RET... + ^ +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-() MATCH ()-[p *]-() RETURN p $$)as (p agtype); +ERROR: duplicate variable 'p' +LINE 1: ...ypher('cypher_vle', $$ MATCH ()-[p *]-() MATCH ()-[p *]-() R... + ^ +SELECT * FROM cypher('cypher_vle', $$ MATCH (p) MATCH ()-[p *]-() RETURN p $$)as (p agtype); +ERROR: variable 'p' is for a vertex +LINE 1: ...* FROM cypher('cypher_vle', $$ MATCH (p) MATCH ()-[p *]-() R... + ^ +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-() MATCH (p) RETURN p $$)as (p agtype); +ERROR: variable 'p' is for a VLE edge +LINE 1: ... cypher('cypher_vle', $$ MATCH ()-[p *]-() MATCH (p) RETURN ... + ^ +SELECT * FROM cypher('cypher_vle', $$ MATCH p=() MATCH ()-[p *]-() RETURN p $$)as (p agtype); +ERROR: variable 'p' already exists +LINE 1: ... FROM cypher('cypher_vle', $$ MATCH p=() MATCH ()-[p *]-() R... + ^ +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-() MATCH p=() RETURN p $$)as (p agtype); +ERROR: variable "p" already exists +LINE 1: ...M cypher('cypher_vle', $$ MATCH ()-[p *]-() MATCH p=() RETUR... + ^ -- -- Clean up -- diff --git a/regress/sql/cypher_match.sql b/regress/sql/cypher_match.sql index 4228d82b3..fb6508423 100644 --- a/regress/sql/cypher_match.sql +++ b/regress/sql/cypher_match.sql @@ -945,6 +945,21 @@ SELECT * FROM cypher('cypher_match', $$ MATCH p=(a)-[b]->()-[b:knows]->(a) RETUR 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); +SELECT * FROM cypher('cypher_match', $$ MATCH p=(p) RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_match', $$ MATCH p=(p)-[]->() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_match', $$ MATCH p=()-[p]->() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_match', $$ MATCH p=() MATCH (p) RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_match', $$ MATCH p=() MATCH (p)-[]->() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_match', $$ MATCH p=() MATCH ()-[p]->() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_match', $$ MATCH (p) MATCH p=() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_match', $$ MATCH ()-[p]->() MATCH p=() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_match', $$ MATCH ()-[p *]-()-[p]-() RETURN 0 $$)as (p agtype); +SELECT * FROM cypher('cypher_match', $$ CREATE (p) WITH p MATCH p=() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_match', $$ CREATE p=() WITH p MATCH (p) RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_match', $$ CREATE ()-[p:knows]->() WITH p MATCH p=() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_match', $$ CREATE p=() WITH p MATCH ()-[p]->() RETURN p $$)as (p agtype); + + -- -- Default alias check (issue #883) diff --git a/regress/sql/cypher_vle.sql b/regress/sql/cypher_vle.sql index 468135eeb..13cf05944 100644 --- a/regress/sql/cypher_vle.sql +++ b/regress/sql/cypher_vle.sql @@ -290,6 +290,21 @@ DROP FUNCTION show_list_use_vle; SELECT drop_graph('mygraph', true); +-- invalid reuse of VLE +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p]-()-[p *]-() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-()-[p]-() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_vle', $$ MATCH (p)-[p *]-() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-(p) RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_vle', $$ MATCH p=()-[p *]-() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-()-[p *]-() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p]-() MATCH ()-[p *]-() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-() MATCH ()-[p]-() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-() MATCH ()-[p *]-() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_vle', $$ MATCH (p) MATCH ()-[p *]-() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-() MATCH (p) RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_vle', $$ MATCH p=() MATCH ()-[p *]-() RETURN p $$)as (p agtype); +SELECT * FROM cypher('cypher_vle', $$ MATCH ()-[p *]-() MATCH p=() RETURN p $$)as (p agtype); + -- -- Clean up -- diff --git a/src/backend/parser/cypher_clause.c b/src/backend/parser/cypher_clause.c index 8697729df..4737600c8 100644 --- a/src/backend/parser/cypher_clause.c +++ b/src/backend/parser/cypher_clause.c @@ -3559,6 +3559,7 @@ static Node *create_property_constraints(cypher_parsestate *cpstate, static List *transform_match_path(cypher_parsestate *cpstate, Query *query, cypher_path *path) { + ParseState *pstate = (ParseState *)cpstate; List *qual = NIL; List *entities = NIL; FuncCall *duplicate_edge_qual; @@ -3572,6 +3573,15 @@ static List *transform_match_path(cypher_parsestate *cpstate, Query *query, { TargetEntry *path_te; + if (findTarget(query->targetList, path->var_name) != NULL) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable \"%s\" already exists", + path->var_name), + parser_errposition(pstate, path->location))); + } + path_te = transform_match_create_path_variable(cpstate, path, entities); query->targetList = lappend(query->targetList, path_te); @@ -3649,13 +3659,51 @@ static transform_entity *transform_VLE_edge_entity(cypher_parsestate *cpstate, /* * If we have a variable name (rel name), make the target entry. Otherwise, - * there isn't a reason to create one. + * there isn't a reason to create one. Additionally, verify that it is not + * reused. */ if (rel->name != NULL) { FuncExpr *fexpr; List *args = list_make1(var); Oid func_oid = InvalidOid; + transform_entity *entity = NULL; + + te = findTarget(query->targetList, rel->name); + entity = find_variable(cpstate, rel->name); + + /* If the variable already exists, error out */ + if (te && entity) + { + if (entity->type == ENT_VERTEX) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable '%s' is for a vertex", rel->name), + parser_errposition(pstate, rel->location))); + } + else if (entity->type == ENT_EDGE) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable '%s' is for an edge", rel->name), + parser_errposition(pstate, rel->location))); + } + else + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("duplicate variable '%s'", rel->name), + parser_errposition(pstate, rel->location))); + } + } + else if (te && !entity) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable '%s' already exists", rel->name), + parser_errposition(pstate, rel->location))); + } /* * Get the oid for the materialize function that returns a list of @@ -3803,11 +3851,22 @@ static List *transform_match_entities(cypher_parsestate *cpstate, Query *query, */ if (node->name != NULL) { + Node *expr; + + if (path->var_name && strcmp(node->name, path->var_name) == 0) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable \"%s\" is for a path", + node->name), + parser_errposition(pstate, node->location))); + } + /* * Checks the previous clauses to see if the variable already * exists. */ - Node *expr = colNameToVar(pstate, node->name, false, + expr = colNameToVar(pstate, node->name, false, node->location); if (expr != NULL) { @@ -3910,6 +3969,16 @@ static List *transform_match_entities(cypher_parsestate *cpstate, Query *query, rel = lfirst(lc); + if (rel->name && path->var_name && + strcmp(rel->name, path->var_name) == 0) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable \"%s\" is for a path", + rel->name), + parser_errposition(pstate, rel->location))); + } + /* * There are 2 edge cases - 1) a regular edge and 2) a VLE edge. * A VLE edge is not added like a regular edge - it is a function. @@ -4326,11 +4395,29 @@ static Expr *transform_cypher_edge(cypher_parsestate *cpstate, } /* If the variable already exists, verify that it is for an edge */ - if (refs_var && entity->type != ENT_EDGE) + if (refs_var) + { + if (entity->type == ENT_VERTEX) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable '%s' is for a vertex", rel->name), + parser_errposition(pstate, rel->location))); + } + else if (entity->type == ENT_VLE_EDGE) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable '%s' is for a VLE edge", rel->name), + parser_errposition(pstate, rel->location))); + } + } + + else if (te && !entity) { ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("variable '%s' is for a vertex", rel->name), + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable '%s' already exists", rel->name), parser_errposition(pstate, rel->location))); } } @@ -4393,7 +4480,7 @@ static Expr *transform_cypher_edge(cypher_parsestate *cpstate, if (expr == NULL && refs_var) { ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + (errcode(ERRCODE_DUPLICATE_ALIAS), errmsg("duplicate edge variable '%s' within a clause", rel->name), parser_errposition(pstate, rel->location))); @@ -4545,11 +4632,32 @@ static Expr *transform_cypher_node(cypher_parsestate *cpstate, } /* If the variable already exists, verify that it is for a vertex */ - if (refs_var && entity->type != ENT_VERTEX) + if (refs_var) + { + if (entity->type == ENT_EDGE) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable '%s' is for an edge", node->name), + parser_errposition(pstate, node->location))); + } + else if (entity->type == ENT_VLE_EDGE) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable '%s' is for a VLE edge", node->name), + parser_errposition(pstate, node->location))); + } + } + + /* If their is a te but no entity, it implies that their is + * some variable that exists but not an edge,vle or a vertex + */ + else if (te && !entity) { ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("variable '%s' is for a edge", node->name), + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable '%s' already exists", node->name), parser_errposition(pstate, node->location))); } }