From ee18bdf80bf02f00ad1736dbc49c1167c28d8768 Mon Sep 17 00:00:00 2001 From: Zainab Saad Date: Fri, 17 May 2024 19:16:25 +0500 Subject: [PATCH] Fix apache#1884 - Ambiguous column reference error in SET clause The error occured due to SET transform not checking if the target entry for the RHS item is already present in the query target list and added the item to tl which resulted in variable name conflict. Instead transformed the item and added to tl only if target entry for the var name could not be found Added regression tests --- regress/expected/cypher_set.out | 72 ++++++++++++++++++++++++++++++ regress/sql/cypher_set.sql | 18 ++++++++ src/backend/parser/cypher_clause.c | 63 +++++++++++++++++++------- 3 files changed, 138 insertions(+), 15 deletions(-) diff --git a/regress/expected/cypher_set.out b/regress/expected/cypher_set.out index 1d24a7f9b..8bbfcc880 100644 --- a/regress/expected/cypher_set.out +++ b/regress/expected/cypher_set.out @@ -988,6 +988,64 @@ SELECT * FROM cypher('issue_1634', $$ MATCH (u) DELETE (u) $$) AS (u agtype); --- (0 rows) +-- +-- Issue 1884: column reference is ambiguous error when returning variable used in the RHS of SET clause +-- +SELECT create_graph('issue_1884'); +NOTICE: graph "issue_1884" has been created + create_graph +-------------- + +(1 row) + +SELECT * FROM cypher('issue_1884', $$ CREATE (n:A), (m:B), (n)-[e:EDGE]->(m) $$) AS (result agtype); + result +-------- +(0 rows) + +SELECT * FROM cypher('issue_1884', $$ MATCH (n) SET n.node=n RETURN n $$) AS (result agtype); + result +------------------------------------------------------------------------------------------------------------------------------------------ + {"id": 844424930131969, "label": "A", "properties": {"node": {"id": 844424930131969, "label": "A", "properties": {}}::vertex}}::vertex + {"id": 1125899906842625, "label": "B", "properties": {"node": {"id": 1125899906842625, "label": "B", "properties": {}}::vertex}}::vertex +(2 rows) + +SELECT * FROM cypher('issue_1884', $$ MATCH (n)-[e]->() SET n.edge=e SET e.startNode = n RETURN n, e $$) AS (n agtype, e agtype); + n | e +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {"id": 844424930131969, "label": "A", "properties": {"edge": {"id": 1407374883553281, "label": "EDGE", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {}}::edge, "node": {"id": 844424930131969, "label": "A", "properties": {}}::vertex}}::vertex | {"id": 1407374883553281, "label": "EDGE", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {"startNode": {"id": 844424930131969, "label": "A", "properties": {"edge": {"id": 1407374883553281, "label": "EDGE", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {}}::edge, "node": {"id": 844424930131969, "label": "A", "properties": {}}::vertex}}::vertex}}::edge +(1 row) + +SELECT * FROM cypher('issue_1884', $$ MATCH (n) WITH n, {a: 1} AS m SET n.int=m.a RETURN n, m $$) AS (n agtype, m agtype); + n | m +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------- + {"id": 844424930131969, "label": "A", "properties": {"int": 1, "edge": {"id": 1407374883553281, "label": "EDGE", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {}}::edge, "node": {"id": 844424930131969, "label": "A", "properties": {}}::vertex}}::vertex | {"a": 1} + {"id": 1125899906842625, "label": "B", "properties": {"int": 1, "node": {"id": 1125899906842625, "label": "B", "properties": {}}::vertex}}::vertex | {"a": 1} +(2 rows) + +SELECT * FROM cypher('issue_1884', $$ MATCH (n)-[e]->(m) SET e.edge=e, e.endNode=m RETURN m, e $$) AS (m agtype, e agtype); + m | e +----------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {"id": 1125899906842625, "label": "B", "properties": {"int": 1, "node": {"id": 1125899906842625, "label": "B", "properties": {}}::vertex}}::vertex | {"id": 1407374883553281, "label": "EDGE", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {"edge": {"id": 1407374883553281, "label": "EDGE", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {"startNode": {"id": 844424930131969, "label": "A", "properties": {"edge": {"id": 1407374883553281, "label": "EDGE", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {}}::edge, "node": {"id": 844424930131969, "label": "A", "properties": {}}::vertex}}::vertex}}::edge, "endNode": {"id": 1125899906842625, "label": "B", "properties": {"int": 1, "node": {"id": 1125899906842625, "label": "B", "properties": {}}::vertex}}::vertex, "startNode": {"id": 844424930131969, "label": "A", "properties": {"edge": {"id": 1407374883553281, "label": "EDGE", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {}}::edge, "node": {"id": 844424930131969, "label": "A", "properties": {}}::vertex}}::vertex}}::edge +(1 row) + +SELECT * FROM cypher('issue_1884', $$ MATCH (n)-[e]->(m) WITH 1 AS a, n, e SET e.int=a, n.int=a RETURN a, n, e $$) AS (a agtype, n agtype, e agtype); + a | n | e +---+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 1 | {"id": 844424930131969, "label": "A", "properties": {"int": 1, "edge": {"id": 1407374883553281, "label": "EDGE", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {}}::edge, "node": {"id": 844424930131969, "label": "A", "properties": {}}::vertex}}::vertex | {"id": 1407374883553281, "label": "EDGE", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {"int": 1, "edge": {"id": 1407374883553281, "label": "EDGE", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {"startNode": {"id": 844424930131969, "label": "A", "properties": {"edge": {"id": 1407374883553281, "label": "EDGE", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {}}::edge, "node": {"id": 844424930131969, "label": "A", "properties": {}}::vertex}}::vertex}}::edge, "endNode": {"id": 1125899906842625, "label": "B", "properties": {"int": 1, "node": {"id": 1125899906842625, "label": "B", "properties": {}}::vertex}}::vertex, "startNode": {"id": 844424930131969, "label": "A", "properties": {"edge": {"id": 1407374883553281, "label": "EDGE", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {}}::edge, "node": {"id": 844424930131969, "label": "A", "properties": {}}::vertex}}::vertex}}::edge +(1 row) + +SELECT * FROM cypher('issue_1884', $$ MERGE (n: C) WITH [u IN [1, 2, 3]] AS u, n SET n.a = u RETURN n, u $$) AS (n agtype, u agtype); + n | u +--------------------------------------------------------------------------------+----------- + {"id": 1688849860263937, "label": "C", "properties": {"a": [1, 2, 3]}}::vertex | [1, 2, 3] +(1 row) + +SELECT * FROM cypher('issue_1884', $$ MATCH (n) DETACH DELETE n $$) AS (result agtype); + result +-------- +(0 rows) + -- -- Clean up -- @@ -1038,6 +1096,20 @@ NOTICE: graph "issue_1634" has been dropped (1 row) +SELECT drop_graph('issue_1884', true); +NOTICE: drop cascades to 6 other objects +DETAIL: drop cascades to table issue_1884._ag_label_vertex +drop cascades to table issue_1884._ag_label_edge +drop cascades to table issue_1884."A" +drop cascades to table issue_1884."B" +drop cascades to table issue_1884."EDGE" +drop cascades to table issue_1884."C" +NOTICE: graph "issue_1884" has been dropped + drop_graph +------------ + +(1 row) + -- -- End -- diff --git a/regress/sql/cypher_set.sql b/regress/sql/cypher_set.sql index a2667153d..28ca642cc 100644 --- a/regress/sql/cypher_set.sql +++ b/regress/sql/cypher_set.sql @@ -379,6 +379,23 @@ SELECT * FROM cypher('issue_1634', $$ MERGE (v:PERSION {id: '1'}) SELECT * FROM cypher('issue_1634', $$ MATCH (u) DELETE (u) $$) AS (u agtype); +-- +-- Issue 1884: column reference is ambiguous error when returning variable used in the RHS of SET clause +-- + +SELECT create_graph('issue_1884'); + +SELECT * FROM cypher('issue_1884', $$ CREATE (n:A), (m:B), (n)-[e:EDGE]->(m) $$) AS (result agtype); + +SELECT * FROM cypher('issue_1884', $$ MATCH (n) SET n.node=n RETURN n $$) AS (result agtype); +SELECT * FROM cypher('issue_1884', $$ MATCH (n)-[e]->() SET n.edge=e SET e.startNode = n RETURN n, e $$) AS (n agtype, e agtype); +SELECT * FROM cypher('issue_1884', $$ MATCH (n) WITH n, {a: 1} AS m SET n.int=m.a RETURN n, m $$) AS (n agtype, m agtype); +SELECT * FROM cypher('issue_1884', $$ MATCH (n)-[e]->(m) SET e.edge=e, e.endNode=m RETURN m, e $$) AS (m agtype, e agtype); +SELECT * FROM cypher('issue_1884', $$ MATCH (n)-[e]->(m) WITH 1 AS a, n, e SET e.int=a, n.int=a RETURN a, n, e $$) AS (a agtype, n agtype, e agtype); +SELECT * FROM cypher('issue_1884', $$ MERGE (n: C) WITH [u IN [1, 2, 3]] AS u, n SET n.a = u RETURN n, u $$) AS (n agtype, u agtype); + +SELECT * FROM cypher('issue_1884', $$ MATCH (n) DETACH DELETE n $$) AS (result agtype); + -- -- Clean up -- @@ -387,6 +404,7 @@ DROP FUNCTION set_test; SELECT drop_graph('cypher_set', true); SELECT drop_graph('cypher_set_1', true); SELECT drop_graph('issue_1634', true); +SELECT drop_graph('issue_1884', true); -- -- End diff --git a/src/backend/parser/cypher_clause.c b/src/backend/parser/cypher_clause.c index 1cbde9a24..240d44f10 100644 --- a/src/backend/parser/cypher_clause.c +++ b/src/backend/parser/cypher_clause.c @@ -1701,6 +1701,7 @@ cypher_update_information *transform_cypher_set_item_list( char *variable_name, *property_name; String *property_node, *variable_node; int is_entire_prop_update = 0; // true if a map is assigned to variable + bool rhs_var_exists = false; // LHS of set_item must be a variable or an indirection. if (IsA(set_item->prop, ColumnRef)) @@ -1836,27 +1837,59 @@ cypher_update_information *transform_cypher_set_item_list( ((cypher_map*)set_item->expr)->keep_null = set_item->is_add; } - // create target entry for the new property value - item->prop_position = (AttrNumber)pstate->p_next_resno; - target_item = transform_cypher_item(cpstate, set_item->expr, NULL, - EXPR_KIND_SELECT_TARGET, NULL, - false); - - if (has_a_cypher_list_comprehension_node(set_item->expr)) + /* + * if the RHS is a ColumnRef and the TargetEntry for the variable + * already exists, no need to transform the RHS item, + * just add volatile wrapper to the target entry of the existing item + */ + if (IsA(set_item->expr, ColumnRef)) { - query->hasAggs = true; + ColumnRef *cref = (ColumnRef *)set_item->expr; + String *cref_str = linitial(cref->fields); + char *prop_name = cref_str->sval; + + int prop_resno = get_target_entry_resno(query->targetList, prop_name); + + if (prop_resno != -1) + { + // RHS variable already exists + rhs_var_exists = true; + item->prop_position = prop_resno; + target_item = findTarget(query->targetList, prop_name); + add_volatile_wrapper_to_target_entry(query->targetList, + item->prop_position); + } } - if (!query->hasAggs && nodeTag(target_item->expr) == T_Aggref) + /* + * if a TargetEntry could not be found for the RHS item, transform the + * item and add to the tl + */ + if (!rhs_var_exists) { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Invalid use of aggregation in this context"), - parser_errposition(pstate, set_item->location))); - } + // create target entry for the new property value + item->prop_position = (AttrNumber)pstate->p_next_resno; + + target_item = transform_cypher_item(cpstate, set_item->expr, NULL, + EXPR_KIND_SELECT_TARGET, NULL, + false); + + if (has_a_cypher_list_comprehension_node(set_item->expr)) + { + query->hasAggs = true; + } - target_item->expr = add_volatile_wrapper(target_item->expr); + if (!query->hasAggs && nodeTag(target_item->expr) == T_Aggref) + { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Invalid use of aggregation in this context"), + parser_errposition(pstate, set_item->location))); + } + + target_item->expr = add_volatile_wrapper(target_item->expr); + query->targetList = lappend(query->targetList, target_item); + } - query->targetList = lappend(query->targetList, target_item); info->set_items = lappend(info->set_items, item); }