From f2e847421c52ea3073a82cc30ad0072d5cd68c58 Mon Sep 17 00:00:00 2001 From: satyanarayana narlapuram Date: Tue, 21 Apr 2026 14:33:33 +0000 Subject: [PATCH v20260430 3/5] Handle nodes that may appear in GraphPattern expression trees expression_tree_mutator_impl() was does not handle T_GraphPattern, T_GraphElementPattern, and T_GraphPropertyRef. The corresponding expression_tree_walker_impl() already handles all three node types. This causes an "unrecognized node type " error whenever a GRAPH_TABLE appeared in an expression tree. While at it also update raw_expression_tree_walker() and expression_tree_walker() to handle missing nodes that may appear in GraphPattern expression trees. When raw_expression_tree_walker() is called, GraphElementPattern::labelexpr does contains ColumnRefs instead of GraphLabelRefs. Hence those are not handled in raw_expression_tree_walker(). Reported by: Satyanarayana Narlapuram Author: Satyanarayana Narlapuram Author: Ashutosh Bapat Reviewed by: Ashutosh Bapat Reviewed by: Robert Haas Discussion: https://www.postgresql.org/message-id/CAHg+QDc97WFTSkXg=g_ZAH8GnY2gJrvq72cs+YjqEAuZgXnkAQ@mail.gmail.com --- src/backend/nodes/nodeFuncs.c | 31 +++++++++++++++++++++++ src/test/regress/expected/graph_table.out | 15 +++++++++++ src/test/regress/sql/graph_table.sql | 9 +++++++ 3 files changed, 55 insertions(+) diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 7edbd5b7225..a712b76eeb1 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -2135,6 +2135,7 @@ expression_tree_walker_impl(Node *node, case T_RangeTblRef: case T_SortGroupClause: case T_CTESearchClause: + case T_GraphLabelRef: case T_GraphPropertyRef: case T_MergeSupportFunc: /* primitive node types with no expression subnodes */ @@ -2698,6 +2699,8 @@ expression_tree_walker_impl(Node *node, { GraphElementPattern *gep = (GraphElementPattern *) node; + if (WALK(gep->labelexpr)) + return true; if (WALK(gep->subexpr)) return true; if (WALK(gep->whereClause)) @@ -3062,6 +3065,8 @@ expression_tree_mutator_impl(Node *node, case T_SortGroupClause: case T_CTESearchClause: case T_MergeSupportFunc: + case T_GraphLabelRef: + case T_GraphPropertyRef: return copyObject(node); case T_WithCheckOption: { @@ -3814,6 +3819,30 @@ expression_tree_mutator_impl(Node *node, return (Node *) newnode; } break; + case T_GraphElementPattern: + { + GraphElementPattern *gep = (GraphElementPattern *) node; + GraphElementPattern *newnode; + + FLATCOPY(newnode, gep, GraphElementPattern); + MUTATE(newnode->labelexpr, gep->labelexpr, Node *); + MUTATE(newnode->subexpr, gep->subexpr, List *); + MUTATE(newnode->whereClause, gep->whereClause, Node *); + newnode->quantifier = list_copy(gep->quantifier); + return (Node *) newnode; + } + break; + case T_GraphPattern: + { + GraphPattern *gp = (GraphPattern *) node; + GraphPattern *newnode; + + FLATCOPY(newnode, gp, GraphPattern); + MUTATE(newnode->path_pattern_list, gp->path_pattern_list, List *); + MUTATE(newnode->whereClause, gp->whereClause, Node *); + return (Node *) newnode; + } + break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); @@ -4796,6 +4825,8 @@ raw_expression_tree_walker_impl(Node *node, { GraphElementPattern *gep = (GraphElementPattern *) node; + if (WALK(gep->labelexpr)) + return true; if (WALK(gep->subexpr)) return true; if (WALK(gep->whereClause)) diff --git a/src/test/regress/expected/graph_table.out b/src/test/regress/expected/graph_table.out index 12b8706b5f3..8038fcd39b7 100644 --- a/src/test/regress/expected/graph_table.out +++ b/src/test/regress/expected/graph_table.out @@ -1032,4 +1032,19 @@ SELECT sname, dname FROM GRAPH_TABLE (g1 MATCH (src)->(dest) WHERE src.vprop1 > ERROR: subqueries within GRAPH_TABLE reference are not supported SELECT sname, dname FROM GRAPH_TABLE (g1 MATCH (src)->(dest) WHERE out_degree(src.vname) > (SELECT max(out_degree(nname)) FROM GRAPH_TABLE (g1 MATCH (node) COLUMNS (node.vname AS nname))) COLUMNS(src.vname AS sname, dest.vname AS dname)); ERROR: subqueries within GRAPH_TABLE reference are not supported +-- GRAPH_TABLE subquery in HAVING clause +SELECT src.vname, count(*) + FROM v1 AS src + GROUP BY src.vname + HAVING count(*) >= (SELECT count(*) + FROM GRAPH_TABLE (g1 MATCH (a IS vl1 | vl2) + COLUMNS (a.vname AS n)) + WHERE n = src.vname); + vname | count +-------+------- + v13 | 1 + v12 | 1 + v11 | 1 +(3 rows) + -- leave the objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/graph_table.sql b/src/test/regress/sql/graph_table.sql index a5df4647b6a..a3681c6c0ef 100644 --- a/src/test/regress/sql/graph_table.sql +++ b/src/test/regress/sql/graph_table.sql @@ -590,4 +590,13 @@ SELECT * FROM customers co WHERE co.customer_id = (SELECT customer_id FROM GRAPH SELECT sname, dname FROM GRAPH_TABLE (g1 MATCH (src)->(dest) WHERE src.vprop1 > (SELECT max(v1.vprop1) FROM v1) COLUMNS(src.vname AS sname, dest.vname AS dname)); SELECT sname, dname FROM GRAPH_TABLE (g1 MATCH (src)->(dest) WHERE out_degree(src.vname) > (SELECT max(out_degree(nname)) FROM GRAPH_TABLE (g1 MATCH (node) COLUMNS (node.vname AS nname))) COLUMNS(src.vname AS sname, dest.vname AS dname)); +-- GRAPH_TABLE subquery in HAVING clause +SELECT src.vname, count(*) + FROM v1 AS src + GROUP BY src.vname + HAVING count(*) >= (SELECT count(*) + FROM GRAPH_TABLE (g1 MATCH (a IS vl1 | vl2) + COLUMNS (a.vname AS n)) + WHERE n = src.vname); + -- leave the objects behind for pg_upgrade/pg_dump tests -- 2.34.1