public inbox for [email protected]  
help / color / mirror / Atom feed
From: Ashutosh Bapat <[email protected]>
To: SATYANARAYANA NARLAPURAM <[email protected]>
Cc: PostgreSQL Hackers <[email protected]>
Subject: Re: [Patch]Add Graph* node support to expression_tree_mutator
Date: Tue, 28 Apr 2026 20:35:11 +0530
Message-ID: <CAExHW5vm8MA_w975hP==OkGhbX2uciinUjRp_Pk310fN5uGW8w@mail.gmail.com> (raw)
In-Reply-To: <CAExHW5swSoFHbL3F8nGKTx-qtk8W9inp0Afxfr+JBsQ6z2tmQw@mail.gmail.com>
References: <CAHg+QDc97WFTSkXg=g_ZAH8GnY2gJrvq72cs+YjqEAuZgXnkAQ@mail.gmail.com>
	<CAExHW5swSoFHbL3F8nGKTx-qtk8W9inp0Afxfr+JBsQ6z2tmQw@mail.gmail.com>

On Thu, Apr 23, 2026 at 12:18 PM Ashutosh Bapat
<[email protected]> wrote:
>
>
> Why is MUTATE not called on GraphElementPattern::labelexpr and
> GraphElementPattern::quantifier?

The walker didn't WALK labelexpr and quantifier either. Given that
labelexpr is a boolean expression it needs to be WALKed. quantifier is
IntList which is ignored by other nodes as well when WALKing. But we
need to copy quantifier in mutator otherwise the mutated expression
will point to the same IntList as the original node. Other nodes also
copy the OidLists and IntLists when mutating them. I have modified the
test query to cover the label expression mutator.

raw_expression_walker didn't cover labelexpr either. Added it there.
The label expression at that stage contains ColumnRef and BoolExpr
which are already covered by raw expression tree walker.

-- 
Best Wishes,
Ashutosh Bapat


Attachments:

  [text/x-patch] v20260428-0001-Handle-nodes-that-may-appear-in-GraphPatte.patch (6.0K, 2-v20260428-0001-Handle-nodes-that-may-appear-in-GraphPatte.patch)
  download | inline diff:
From f0c7384ee37cf0b64d54efb53b2d97600ebdb928 Mon Sep 17 00:00:00 2001
From: satyanarayana narlapuram <[email protected]>
Date: Tue, 21 Apr 2026 14:33:33 +0000
Subject: [PATCH v20260428 3/3] Handle nodes that may appear in GraphPattern
 expression trees

expression_tree_mutator_impl() was missing case handlers for T_GraphPattern,
T_GraphElementPattern, and T_GraphPropertyRef.  The corresponding
expression_tree_walker_impl() already handled all three node types, but the
mutator did not, causing 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 <[email protected]>
Author: Satyanarayana Narlapuram <[email protected]>
Author: Ashutosh Bapat <[email protected]>
Reviewed by: Ashutosh Bapat <[email protected]>
Discussion: https://www.postgresql.org/message-id/CAHg+QDc97WFTSkXg=g_ZAH8GnY2gJrvq72cs+YjqEAuZgXnkAQ@mail.gmail.com
---
 src/backend/nodes/nodeFuncs.c             | 45 +++++++++++++++++++++++
 src/test/regress/expected/graph_table.out | 15 ++++++++
 src/test/regress/sql/graph_table.sql      |  9 +++++
 3 files changed, 69 insertions(+)

diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 7edbd5b7225..db2eff343d7 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))
@@ -3814,6 +3817,46 @@ expression_tree_mutator_impl(Node *node,
 				return (Node *) newnode;
 			}
 			break;
+		case T_GraphLabelRef:
+			{
+				GraphLabelRef *newnode;
+
+				FLATCOPY(newnode, node, GraphLabelRef);
+				return (Node *) newnode;
+			}
+			break;
+		case T_GraphPropertyRef:
+			{
+				GraphPropertyRef *newnode;
+
+				FLATCOPY(newnode, node, GraphPropertyRef);
+				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 +4839,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



view thread (7+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected]
  Subject: Re: [Patch]Add Graph* node support to expression_tree_mutator
  In-Reply-To: <CAExHW5vm8MA_w975hP==OkGhbX2uciinUjRp_Pk310fN5uGW8w@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox