Skip to content

Commit ae2b956

Browse files
Add expression tree walkers for cypher nodes
- Added cypher_raw_expr_tree_walker and cypher_expr_tree_walker, based on Postgres's raw_expression_tree_walker and expression_tree_walker. These follow the same walker API as Postgres and add support for Cypher-specific nodes. - Also added the agtype[] to agtype func and typecast to 1.5.0-y.y.y.sql - Simplifies logic for cypher_subquery handling in where clause. - Fixes a crash when list comprehension in the WHERE clause references a variable from the preceding MATCH clause.
1 parent acd1046 commit ae2b956

File tree

9 files changed

+198
-363
lines changed

9 files changed

+198
-363
lines changed

age--1.5.0--y.y.y.sql

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,15 @@ PARALLEL SAFE
137137
AS 'MODULE_PATHNAME';
138138

139139
CREATE CAST (agtype AS json)
140-
WITH FUNCTION ag_catalog.agtype_to_json(agtype);
140+
WITH FUNCTION ag_catalog.agtype_to_json(agtype);
141+
142+
CREATE FUNCTION ag_catalog.agtype_array_to_agtype(agtype[])
143+
RETURNS agtype
144+
LANGUAGE c
145+
IMMUTABLE
146+
RETURNS NULL ON NULL INPUT
147+
PARALLEL SAFE
148+
AS 'MODULE_PATHNAME';
149+
150+
CREATE CAST (agtype[] AS agtype)
151+
WITH FUNCTION ag_catalog.agtype_array_to_agtype(agtype[]);

regress/expected/list_comprehension.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,18 @@ SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list: [0, 2, 4, 6, 8, 10
707707
ERROR: Invalid use of aggregation in this context
708708
LINE 1: ... $$ MATCH (u {list: [0, 2, 4, 6, 8, 10, 12]}) SET u.c = coll...
709709
^
710+
SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list: [0, 2, 4, 6, 8, 10, 12]}) WHERE u.list = [u IN [1, u]] RETURN u $$) AS (u agtype);
711+
u
712+
---
713+
(0 rows)
714+
715+
SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list: [0, 2, 4, 6, 8, 10, 12]}) WHERE u.list IN [u IN [1, u.list]] RETURN u $$) AS (u agtype);
716+
u
717+
---------------------------------------------------------------------------------------------------------------------------------------------------------------
718+
{"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
719+
{"id": 281474976710668, "label": "", "properties": {"b": [0, 1, 2, 3, 4, 5], "c": [0, 2, 4, 6, 8, 10, 12], "list": [0, 2, 4, 6, 8, 10, 12]}}::vertex
720+
(2 rows)
721+
710722
-- Clean up
711723
SELECT * FROM drop_graph('list_comprehension', true);
712724
NOTICE: drop cascades to 4 other objects

regress/sql/list_comprehension.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ SELECT * FROM cypher('list_comprehension', $$ CREATE (u {list: [0, 2, 4, 6, 8, 1
171171
SELECT * FROM cypher('list_comprehension', $$ WITH [1, 2, 3] AS u UNWIND collect(u) AS v RETURN v $$) AS (result agtype);
172172
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 (result agtype);
173173
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);
174+
SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list: [0, 2, 4, 6, 8, 10, 12]}) WHERE u.list = [u IN [1, u]] RETURN u $$) AS (u agtype);
175+
SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list: [0, 2, 4, 6, 8, 10, 12]}) WHERE u.list IN [u IN [1, u.list]] RETURN u $$) AS (u agtype);
174176

175177
-- Clean up
176178
SELECT * FROM drop_graph('list_comprehension', true);

src/backend/nodes/cypher_outfuncs.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ void out_cypher_with(StringInfo str, const ExtensibleNode *node)
117117
DEFINE_AG_NODE(cypher_with);
118118

119119
WRITE_BOOL_FIELD(distinct);
120-
WRITE_BOOL_FIELD(subquery_intermediate);
121120
WRITE_NODE_FIELD(items);
122121
WRITE_NODE_FIELD(order_by);
123122
WRITE_NODE_FIELD(skip);

src/backend/optimizer/cypher_pathnode.c

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@
2323

2424
#include "optimizer/cypher_createplan.h"
2525
#include "optimizer/cypher_pathnode.h"
26+
#include "parser/cypher_analyze.h"
2627
#include "executor/cypher_utils.h"
2728
#include "optimizer/subselect.h"
2829
#include "nodes/makefuncs.h"
2930

3031
static Const *convert_sublink_to_subplan(PlannerInfo *root,
3132
List *custom_private);
32-
static bool has_sublink(Node *node);
33+
static bool expr_has_sublink(Node *node, void *context);
3334

3435
const CustomPathMethods cypher_create_path_methods = {
3536
CREATE_PATH_NAME, plan_cypher_create_path, NULL};
@@ -236,12 +237,10 @@ static Const *convert_sublink_to_subplan(PlannerInfo *root, List *custom_private
236237
{
237238
cypher_target_node *node = (cypher_target_node *)lfirst(lc);
238239
Node *prop_expr = (Node *) node->prop_expr;
239-
if (prop_expr != NULL)
240+
241+
if (expr_has_sublink(prop_expr, NULL))
240242
{
241-
if (has_sublink(prop_expr))
242-
{
243-
node->prop_expr = (Expr *) SS_process_sublinks(root, prop_expr, false);
244-
}
243+
node->prop_expr = (Expr *) SS_process_sublinks(root, prop_expr, false);
245244
}
246245
}
247246

@@ -252,26 +251,20 @@ static Const *convert_sublink_to_subplan(PlannerInfo *root, List *custom_private
252251
PointerGetDatum(str->data), false, false);
253252
}
254253

255-
/* Helper function to check if the node is SubLink or has it embedded */
256-
static bool has_sublink(Node *node)
254+
/*
255+
* Helper function to check if the node has a sublink.
256+
*/
257+
static bool expr_has_sublink(Node *node, void *context)
257258
{
258259
if (node == NULL)
260+
{
259261
return false;
262+
}
260263

261264
if (IsA(node, SubLink))
262-
return true;
263-
264-
if (IsA(node, FuncExpr))
265265
{
266-
FuncExpr *fe = (FuncExpr *) node;
267-
ListCell *lc;
268-
269-
foreach(lc, fe->args)
270-
{
271-
if (has_sublink((Node *) lfirst(lc)))
272-
return true;
273-
}
266+
return true;
274267
}
275268

276-
return false;
269+
return cypher_expr_tree_walker(node, expr_has_sublink, context);
277270
}

0 commit comments

Comments
 (0)