Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix aggref found where not expected issue in list comprehension #189

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 121 additions & 1 deletion regress/expected/list_comprehension.out
Original file line number Diff line number Diff line change
@@ -361,6 +361,118 @@ SELECT * FROM cypher('list_comprehension', $$ WITH [u IN [1,2,3]] AS a CREATE (u
{"id": 281474976710663, "label": "", "properties": {"list": [1, 2, 3]}}::vertex
(1 row)

-- List comprehension in the WITH WHERE clause
SELECT * FROM cypher('list_comprehension', $$ MATCH(u) WITH u WHERE u.list = [u IN [0, 2, 4, 6, 8, 10, 12]] RETURN u $$) AS (u agtype);
u
-----------------------------------------------------------------------------------------------
{"id": 281474976710657, "label": "", "properties": {"list": [0, 2, 4, 6, 8, 10, 12]}}::vertex
(1 row)

SELECT * FROM cypher('list_comprehension', $$ MATCH(u) WITH u WHERE u.list = [u IN [0, 2, 4, 6, 8, 10, 12]] OR size(u.list) = 0 RETURN u $$) AS (u agtype);
u
-----------------------------------------------------------------------------------------------
{"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
{"id": 281474976710657, "label": "", "properties": {"list": [0, 2, 4, 6, 8, 10, 12]}}::vertex
(2 rows)

SELECT * FROM cypher('list_comprehension', $$ MATCH(u) WITH u WHERE u.list = [u IN [0, 2, 4, 6, 8, 10, 12]] OR size(u.list)::bool RETURN u $$) AS (u agtype);
u
--------------------------------------------------------------------------------------------------------
{"id": 281474976710658, "label": "", "properties": {"list": [1, 3, 5, 7, 9, 11, 13]}}::vertex
{"id": 281474976710661, "label": "", "properties": {"list": [6, 8, 10, 12]}}::vertex
{"id": 281474976710660, "label": "", "properties": {"list": [12, 14, 16, 18, 20, 22, 24]}}::vertex
{"id": 281474976710662, "label": "", "properties": {"list": [25.0, 49.0, 81.0, 121.0, 169.0]}}::vertex
{"id": 281474976710657, "label": "", "properties": {"list": [0, 2, 4, 6, 8, 10, 12]}}::vertex
{"id": 281474976710663, "label": "", "properties": {"list": [1, 2, 3]}}::vertex
(6 rows)

SELECT * FROM cypher('list_comprehension', $$ MATCH(u) WITH u WHERE u.list = [u IN [0, 2, 4, 6, 8, 10, 12]] OR NOT size(u.list)::bool RETURN u $$) AS (u agtype);
u
-----------------------------------------------------------------------------------------------
{"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
{"id": 281474976710657, "label": "", "properties": {"list": [0, 2, 4, 6, 8, 10, 12]}}::vertex
(2 rows)

SELECT * FROM cypher('list_comprehension', $$ CREATE(u:csm_match {list: ['abc', 'def', 'ghi']}) $$) AS (u agtype);
u
---
(0 rows)

SELECT * FROM cypher('list_comprehension', $$ MATCH(u: csm_match) WITH u WHERE [u IN u.list][0] STARTS WITH "ab" RETURN u $$) AS (u agtype);
u
------------------------------------------------------------------------------------------------------
{"id": 844424930131969, "label": "csm_match", "properties": {"list": ["abc", "def", "ghi"]}}::vertex
(1 row)

SELECT * FROM cypher('list_comprehension', $$ WITH [1, 2, 3] AS u WHERE u = [u IN [1, 2, 3]] RETURN u $$) AS (u agtype);
u
-----------
[1, 2, 3]
(1 row)

SELECT * FROM cypher('list_comprehension', $$ WITH 1 AS u WHERE u = [u IN [1, 2, 3]][0] RETURN u $$) AS (u agtype);
u
---
1
(1 row)

SELECT * FROM cypher('list_comprehension', $$ WITH ['abc', 'defgh'] AS u WHERE [v In u][1] STARTS WITH 'de' RETURN u $$) AS (u agtype);
u
------------------
["abc", "defgh"]
(1 row)

-- List comprehension in UNWIND
SELECT * FROM cypher('list_comprehension', $$ UNWIND [u IN [1, 2, 3]] AS u RETURN u $$) AS (u agtype);
u
---
1
2
3
(3 rows)

SELECT * FROM cypher('list_comprehension', $$ UNWIND [u IN [1, 2, 3] WHERE u > 1 | u*2] AS u RETURN u $$) AS (u agtype);
u
---
4
6
(2 rows)

-- invalid use of aggregation in UNWIND
SELECT * FROM cypher('list_comprehension', $$ WITH [1, 2, 3] AS u UNWIND collect(u) AS v RETURN v $$) AS (u agtype);
ERROR: Invalid use of aggregation in this context
LINE 1: ...ist_comprehension', $$ WITH [1, 2, 3] AS u UNWIND collect(u)...
^
-- List comprehension in SET
SELECT * FROM cypher('list_comprehension', $$ MATCH(u {list: [0, 2, 4, 6, 8, 10, 12]}) SET u.a = [u IN range(0, 5)] RETURN u $$) AS (u agtype);
u
------------------------------------------------------------------------------------------------------------------------
{"id": 281474976710657, "label": "", "properties": {"a": [0, 1, 2, 3, 4, 5], "list": [0, 2, 4, 6, 8, 10, 12]}}::vertex
(1 row)

SELECT * FROM cypher('list_comprehension', $$ MATCH(u {list: [0, 2, 4, 6, 8, 10, 12]}) SET u.a = [u IN []] RETURN u $$) AS (u agtype);
u
--------------------------------------------------------------------------------------------------------
{"id": 281474976710657, "label": "", "properties": {"a": [], "list": [0, 2, 4, 6, 8, 10, 12]}}::vertex
(1 row)

SELECT * FROM cypher('list_comprehension', $$ MATCH(u {list: [0, 2, 4, 6, 8, 10, 12]}) SET u += {b: [u IN range(0, 5)]} RETURN u $$) AS (u agtype);
u
---------------------------------------------------------------------------------------------------------------------------------
{"id": 281474976710657, "label": "", "properties": {"a": [], "b": [0, 1, 2, 3, 4, 5], "list": [0, 2, 4, 6, 8, 10, 12]}}::vertex
(1 row)

SELECT * FROM cypher('list_comprehension', $$ MATCH(u {list: [0, 2, 4, 6, 8, 10, 12]}) WITh u, collect(u.list) AS v SET u += {b: [u IN range(0, 5)]} SET u.c = [u IN v[0]] RETURN u $$) AS (u agtype);
u
---------------------------------------------------------------------------------------------------------------------------------------------------------------
{"id": 281474976710657, "label": "", "properties": {"a": [], "b": [0, 1, 2, 3, 4, 5], "c": [0, 2, 4, 6, 8, 10, 12], "list": [0, 2, 4, 6, 8, 10, 12]}}::vertex
(1 row)

-- invalid use of aggregation in SET
SELECT * FROM cypher('list_comprehension', $$ MATCH(u {list: [0, 2, 4, 6, 8, 10, 12]}) SET u.c = collect(u.list) RETURN u $$) AS (u agtype);
ERROR: Invalid use of aggregation in this context
LINE 1: ..., $$ MATCH(u {list: [0, 2, 4, 6, 8, 10, 12]}) SET u.c = coll...
^
-- Known issue
SELECT * FROM cypher('list_comprehension', $$ MERGE (u {list:[i IN [1,2,3]]}) RETURN u $$) AS (result agtype);
ERROR: Aggref found in non-Agg plan node
@@ -383,6 +495,12 @@ SELECT * FROM cypher('list_comprehension', $$ WITH [m IN [1,2,3]] AS m RETURN [m
[1, 2, 3] | [1, 2, 3]
(1 row)

SELECT * FROM cypher('list_comprehension', $$ CREATE n=()-[:edge]->() RETURN [n IN nodes(n)] $$) AS (u agtype);
u
----------------------------------------------------------------------------------------------------------------------------------
[{"id": 281474976710664, "label": "", "properties": {}}::vertex, {"id": 281474976710665, "label": "", "properties": {}}::vertex]
(1 row)

-- Multiple list comprehensions in RETURN and WITH clause
SELECT * FROM cypher('list_comprehension', $$ RETURN [u IN [1,2,3]], [u IN [1,2,3]] $$) AS (result agtype, result2 agtype);
result | result2
@@ -454,9 +572,11 @@ ERROR: could not find rte for i
LINE 1: ...$$ RETURN [i IN range(0, 10, 2) WHERE i>5 | i^2], i $$) AS (...
^
SELECT * FROM drop_graph('list_comprehension', true);
NOTICE: drop cascades to 2 other objects
NOTICE: drop cascades to 4 other objects
DETAIL: drop cascades to table list_comprehension._ag_label_vertex
drop cascades to table list_comprehension._ag_label_edge
drop cascades to table list_comprehension.csm_match
drop cascades to table list_comprehension.edge
NOTICE: graph "list_comprehension" has been dropped
drop_graph
------------
30 changes: 30 additions & 0 deletions regress/sql/list_comprehension.sql
Original file line number Diff line number Diff line change
@@ -88,13 +88,43 @@ SELECT * FROM cypher('list_comprehension', $$ CREATE (u {list:[i IN range(0,12,2
SELECT * FROM cypher('list_comprehension', $$ CREATE (u {list:[i IN range(1,13,2) WHERE i>4 | i^2]}) RETURN u $$) AS (result agtype);
SELECT * FROM cypher('list_comprehension', $$ WITH [u IN [1,2,3]] AS a CREATE (u {list:a}) RETURN u $$) AS (result agtype);

-- List comprehension in the WITH WHERE clause
SELECT * FROM cypher('list_comprehension', $$ MATCH(u) WITH u WHERE u.list = [u IN [0, 2, 4, 6, 8, 10, 12]] RETURN u $$) AS (u agtype);
SELECT * FROM cypher('list_comprehension', $$ MATCH(u) WITH u WHERE u.list = [u IN [0, 2, 4, 6, 8, 10, 12]] OR size(u.list) = 0 RETURN u $$) AS (u agtype);
SELECT * FROM cypher('list_comprehension', $$ MATCH(u) WITH u WHERE u.list = [u IN [0, 2, 4, 6, 8, 10, 12]] OR size(u.list)::bool RETURN u $$) AS (u agtype);
SELECT * FROM cypher('list_comprehension', $$ MATCH(u) WITH u WHERE u.list = [u IN [0, 2, 4, 6, 8, 10, 12]] OR NOT size(u.list)::bool RETURN u $$) AS (u agtype);

SELECT * FROM cypher('list_comprehension', $$ CREATE(u:csm_match {list: ['abc', 'def', 'ghi']}) $$) AS (u agtype);
SELECT * FROM cypher('list_comprehension', $$ MATCH(u: csm_match) WITH u WHERE [u IN u.list][0] STARTS WITH "ab" RETURN u $$) AS (u agtype);

SELECT * FROM cypher('list_comprehension', $$ WITH [1, 2, 3] AS u WHERE u = [u IN [1, 2, 3]] RETURN u $$) AS (u agtype);
SELECT * FROM cypher('list_comprehension', $$ WITH 1 AS u WHERE u = [u IN [1, 2, 3]][0] RETURN u $$) AS (u agtype);
SELECT * FROM cypher('list_comprehension', $$ WITH ['abc', 'defgh'] AS u WHERE [v In u][1] STARTS WITH 'de' RETURN u $$) AS (u agtype);

-- List comprehension in UNWIND
SELECT * FROM cypher('list_comprehension', $$ UNWIND [u IN [1, 2, 3]] AS u RETURN u $$) AS (u agtype);
SELECT * FROM cypher('list_comprehension', $$ UNWIND [u IN [1, 2, 3] WHERE u > 1 | u*2] AS u RETURN u $$) AS (u agtype);

-- invalid use of aggregation in UNWIND
SELECT * FROM cypher('list_comprehension', $$ WITH [1, 2, 3] AS u UNWIND collect(u) AS v RETURN v $$) AS (u agtype);

-- List comprehension in SET
SELECT * FROM cypher('list_comprehension', $$ MATCH(u {list: [0, 2, 4, 6, 8, 10, 12]}) SET u.a = [u IN range(0, 5)] RETURN u $$) AS (u agtype);
SELECT * FROM cypher('list_comprehension', $$ MATCH(u {list: [0, 2, 4, 6, 8, 10, 12]}) SET u.a = [u IN []] RETURN u $$) AS (u agtype);
SELECT * FROM cypher('list_comprehension', $$ MATCH(u {list: [0, 2, 4, 6, 8, 10, 12]}) SET u += {b: [u IN range(0, 5)]} RETURN u $$) AS (u agtype);
SELECT * FROM cypher('list_comprehension', $$ MATCH(u {list: [0, 2, 4, 6, 8, 10, 12]}) WITh u, collect(u.list) AS v SET u += {b: [u IN range(0, 5)]} SET u.c = [u IN v[0]] RETURN u $$) AS (u agtype);

-- invalid use of aggregation in SET
SELECT * FROM cypher('list_comprehension', $$ MATCH(u {list: [0, 2, 4, 6, 8, 10, 12]}) SET u.c = collect(u.list) RETURN u $$) AS (u agtype);

-- Known issue
SELECT * FROM cypher('list_comprehension', $$ MERGE (u {list:[i IN [1,2,3]]}) RETURN u $$) AS (result agtype);

-- List comprehension variable scoping
SELECT * FROM cypher('list_comprehension', $$ WITH 1 AS m, [m IN [1, 2, 3]] AS n RETURN [m IN [1, 2, 3]] $$) AS (result agtype);
SELECT * FROM cypher('list_comprehension', $$ WITH 1 AS m RETURN [m IN [1, 2, 3]], m $$) AS (result agtype, result2 agtype);
SELECT * FROM cypher('list_comprehension', $$ WITH [m IN [1,2,3]] AS m RETURN [m IN [1, 2, 3]], m $$) AS (result agtype, result2 agtype);
SELECT * FROM cypher('list_comprehension', $$ CREATE n=()-[:edge]->() RETURN [n IN nodes(n)] $$) AS (u agtype);

-- Multiple list comprehensions in RETURN and WITH clause
SELECT * FROM cypher('list_comprehension', $$ RETURN [u IN [1,2,3]], [u IN [1,2,3]] $$) AS (result agtype, result2 agtype);
24 changes: 23 additions & 1 deletion src/backend/parser/cypher_clause.c
Original file line number Diff line number Diff line change
@@ -1328,6 +1328,8 @@ static Query *transform_cypher_unwind(cypher_parsestate *cpstate,
TargetEntry *te;
ParseNamespaceItem *pnsi;
bool is_list_comp = self->collect != NULL;
bool has_agg =
is_list_comp || has_a_cypher_list_comprehension_node(self->target->val);

query = makeNode(Query);
query->commandType = CMD_SELECT;
@@ -1362,6 +1364,13 @@ static Query *transform_cypher_unwind(cypher_parsestate *cpstate,
expr = transform_cypher_expr(cpstate, self->target->val,
EXPR_KIND_SELECT_TARGET);

if (!has_agg && nodeTag(expr) == T_Aggref)
{
ereport(ERROR, errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Invalid use of aggregation in this context"),
parser_errposition(pstate, self->target->location));
}

unwind = makeFuncCall(list_make1(makeString("age_unnest")), NIL,
COERCE_SQL_SYNTAX, -1);

@@ -1373,7 +1382,7 @@ static Query *transform_cypher_unwind(cypher_parsestate *cpstate,
target_syntax_loc);

pstate->p_expr_kind = old_expr_kind;
pstate->p_hasAggs = is_list_comp;
pstate->p_hasAggs = has_agg;

te = makeTargetEntry((Expr *) funcexpr,
(AttrNumber) pstate->p_next_resno++,
@@ -1799,6 +1808,19 @@ cypher_update_information *transform_cypher_set_item_list(
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;
}

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);
3 changes: 2 additions & 1 deletion src/backend/parser/cypher_expr.c
Original file line number Diff line number Diff line change
@@ -339,7 +339,8 @@ static Node *transform_ColumnRef(cypher_parsestate *cpstate, ColumnRef *cref)

if (cpstate->p_list_comp &&
(pstate->p_expr_kind == EXPR_KIND_WHERE ||
pstate->p_expr_kind == EXPR_KIND_SELECT_TARGET))
pstate->p_expr_kind == EXPR_KIND_SELECT_TARGET) &&
list_length(pstate->p_namespace) > 0)
{
/*
* Just scan through the last pnsi(that is for list comp)
2 changes: 1 addition & 1 deletion src/backend/parser/cypher_gram.y
Original file line number Diff line number Diff line change
@@ -77,7 +77,7 @@
CALL CASE COALESCE CONTAINS CREATE
DELETE DESC DESCENDING DETACH DISTINCT
ELSE END_P ENDS EXISTS EXPLAIN
FALSE_P FOR
FALSE_P
IN IS
LIMIT
MATCH MERGE
71 changes: 57 additions & 14 deletions src/backend/parser/cypher_item.c
Original file line number Diff line number Diff line change
@@ -88,16 +88,23 @@ bool has_a_cypher_list_comprehension_node(Node *expr)
*/
A_Expr *a_expr = (A_Expr *)expr;

// check the left node
if (has_a_cypher_list_comprehension_node(a_expr->lexpr))
{
return true;
}
return (has_a_cypher_list_comprehension_node(a_expr->lexpr) ||
has_a_cypher_list_comprehension_node(a_expr->rexpr));
}
case T_BoolExpr:
{
BoolExpr *bexpr = (BoolExpr *)expr;
ListCell *lc;

// check the right node
if (has_a_cypher_list_comprehension_node(a_expr->rexpr))
// is any of the boolean expression argument a list comprehension?
foreach(lc, bexpr->args)
{
return true;
Node *arg = lfirst(lc);

if (has_a_cypher_list_comprehension_node(arg))
{
return true;
}
}
break;
}
@@ -115,13 +122,10 @@ bool has_a_cypher_list_comprehension_node(Node *expr)
{
cypher_unwind *cu = (cypher_unwind *)expr;

// if it has a collect node, return true
if (cu->collect != NULL)
{
return true;
}
// it is a list comprehension if it has a collect node
return cu->collect != NULL;
}
if (is_ag_node(expr, cypher_map))
else if (is_ag_node(expr, cypher_map))
{
cypher_map *map;
int i;
@@ -148,6 +152,45 @@ bool has_a_cypher_list_comprehension_node(Node *expr)
}
}
}
else if (is_ag_node(expr, cypher_string_match))
{
MuhammadTahaNaveed marked this conversation as resolved.
Show resolved Hide resolved
cypher_string_match *csm_match = (cypher_string_match *)expr;

// is lhs or rhs of the string match a list comprehension?
return (has_a_cypher_list_comprehension_node(csm_match->lhs) ||
has_a_cypher_list_comprehension_node(csm_match->rhs));
}
else if (is_ag_node(expr, cypher_typecast))
{
cypher_typecast *ctypecast = (cypher_typecast *)expr;

// is expr being typecasted a list comprehension?
return has_a_cypher_list_comprehension_node(ctypecast->expr);
}
else if (is_ag_node(expr, cypher_comparison_aexpr))
{
cypher_comparison_aexpr *aexpr = (cypher_comparison_aexpr *)expr;

// is left or right argument a list comprehension?
return (has_a_cypher_list_comprehension_node(aexpr->lexpr) ||
has_a_cypher_list_comprehension_node(aexpr->rexpr));
}
else if (is_ag_node(expr, cypher_comparison_boolexpr))
{
cypher_comparison_boolexpr *bexpr = (cypher_comparison_boolexpr *)expr;
ListCell *lc;

// is any of the boolean expression argument a list comprehension?
foreach(lc, bexpr->args)
{
Node *arg = lfirst(lc);

if (has_a_cypher_list_comprehension_node(arg))
{
return true;
}
}
}
break;
}
default: