From 6b54b4409df4ce1e8ba50c615e10e5cce3cea075 Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Date: Tue, 21 Apr 2026 11:43:43 +0530
Subject: [PATCH v20260421 4/4] pg_get_viewdef() and lateral references in
 COLUMNS of GRAPH_TABLE

Expressions in GRAPH_TABLE COLUMNS list may have lateral references.
get_rule_expr() requires lateral namespaces to deparse such references.
get_from_clause_item() does not pass them when processing the
expressions in COLUMNS list causing ERROR "bogus varlevelsup: 0 offset
0".  Fix get_from_clause_item() to pass input deparse_context containing
lateral namespaces to get_rule_expr() instead of the dummy context.

Reported By: SATYANARAYANA NARLAPURAM <satyanarlapuram@gmail.com>
Author: SATYANARAYANA NARLAPURAM <satyanarlapuram@gmail.com>
Reviewed By: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
---
 src/backend/utils/adt/ruleutils.c         | 10 ++-------
 src/test/regress/expected/graph_table.out | 26 ++++++++++++++++-------
 src/test/regress/sql/graph_table.sql      | 12 +++++++++--
 3 files changed, 30 insertions(+), 18 deletions(-)

diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 78587d223cb..c781cdc84d3 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -13091,22 +13091,16 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
 				get_graph_pattern_def(rte->graph_pattern, context);
 				appendStringInfoString(buf, " COLUMNS (");
 				{
-					ListCell   *lc;
 					bool		first = true;
 
-					foreach(lc, rte->graph_table_columns)
+					foreach_node(TargetEntry, te, rte->graph_table_columns)
 					{
-						TargetEntry *te = lfirst_node(TargetEntry, lc);
-						deparse_context context = {0};
-
 						if (!first)
 							appendStringInfoString(buf, ", ");
 						else
 							first = false;
 
-						context.buf = buf;
-
-						get_rule_expr((Node *) te->expr, &context, false);
+						get_rule_expr((Node *) te->expr, context, false);
 						appendStringInfoString(buf, " AS ");
 						appendStringInfoString(buf, quote_identifier(te->resname));
 					}
diff --git a/src/test/regress/expected/graph_table.out b/src/test/regress/expected/graph_table.out
index 057f283c43d..12b8706b5f3 100644
--- a/src/test/regress/expected/graph_table.out
+++ b/src/test/regress/expected/graph_table.out
@@ -264,7 +264,6 @@ SELECT x1.a, g.* FROM x1, GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.addr
 ERROR:  non-local element variable reference is not supported
 LINE 1: ...tomers WHERE c.address = 'US' AND c.customer_id = x1.a)-[IS ...
                                                              ^
-DROP TABLE x1;
 CREATE TABLE v1 (
     id int PRIMARY KEY,
     vname varchar(10),
@@ -922,14 +921,25 @@ SELECT * FROM GRAPH_TABLE (g4 MATCH (s WHERE s.id = 3)-[e]-(d) COLUMNS (s.val, e
 (2 rows)
 
 -- ruleutils reverse parsing
-CREATE VIEW customers_us AS SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.address = 'US')-[IS customer_orders | customer_wishlists ]->(l IS orders | wishlists)-[ IS list_items]->(p IS products) COLUMNS (c.name AS customer_name, p.name AS product_name)) ORDER BY customer_name, product_name;
+-- The query in the view definition is intentionally complex to test one view with many
+-- features like label disjunction, lateral references, WHERE clauses in graph
+-- patterns.
+CREATE VIEW customers_us AS
+SELECT g.* FROM x1,
+                GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.address = 'US' AND c.customer_id = x1.a)
+                                          -[IS customer_orders | customer_wishlists ]->
+                                          (l IS orders | wishlists)-[ IS list_items]->(p IS products)
+                                    COLUMNS (c.name AS customer_name, p.name AS product_name, x1.a AS a)) g
+           ORDER BY customer_name, product_name;
 SELECT pg_get_viewdef('customers_us'::regclass);
-                                                                                                                     pg_get_viewdef                                                                                                                     
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-  SELECT customer_name,                                                                                                                                                                                                                                +
-     product_name                                                                                                                                                                                                                                      +
-    FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE ((c.address)::text = 'US'::text))-[IS customer_orders|customer_wishlists]->(l IS orders|wishlists)-[IS list_items]->(p IS products) COLUMNS (c.name AS customer_name, p.name AS product_name))+
-   ORDER BY customer_name, product_name;
+                                                                                                                                        pg_get_viewdef                                                                                                                                        
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+  SELECT g.customer_name,                                                                                                                                                                                                                                                                    +
+     g.product_name,                                                                                                                                                                                                                                                                         +
+     g.a                                                                                                                                                                                                                                                                                     +
+    FROM x1,                                                                                                                                                                                                                                                                                 +
+     GRAPH_TABLE (myshop MATCH (c IS customers WHERE (((c.address)::text = 'US'::text) AND (c.customer_id = x1.a)))-[IS customer_orders|customer_wishlists]->(l IS orders|wishlists)-[IS list_items]->(p IS products) COLUMNS (c.name AS customer_name, p.name AS product_name, x1.a AS a)) g+
+   ORDER BY g.customer_name, g.product_name;
 (1 row)
 
 -- test view/graph nesting
diff --git a/src/test/regress/sql/graph_table.sql b/src/test/regress/sql/graph_table.sql
index 278064818ff..a5df4647b6a 100644
--- a/src/test/regress/sql/graph_table.sql
+++ b/src/test/regress/sql/graph_table.sql
@@ -162,7 +162,6 @@ SELECT x1.a, g.* FROM x1, GRAPH_TABLE (myshop MATCH (x1 IS customers WHERE x1.ad
 -- reference is available
 SELECT x1.a, g.* FROM x1, GRAPH_TABLE (myshop MATCH (x1 IS customers)-[IS customer_orders]->(o IS orders WHERE o.order_id = x1.a) COLUMNS (x1.name AS customer_name, x1.customer_id AS cid, o.order_id)) g; -- error
 SELECT x1.a, g.* FROM x1, GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.address = 'US' AND c.customer_id = x1.a)-[IS customer_orders]->(x1 IS orders) COLUMNS (c.name AS customer_name, c.customer_id AS cid, x1.order_id)) g; -- error
-DROP TABLE x1;
 
 CREATE TABLE v1 (
     id int PRIMARY KEY,
@@ -525,7 +524,16 @@ SELECT * FROM GRAPH_TABLE (g4 MATCH (s)-[e]-(d) WHERE s.id = 3 COLUMNS (s.val, e
 SELECT * FROM GRAPH_TABLE (g4 MATCH (s WHERE s.id = 3)-[e]-(d) COLUMNS (s.val, e.val, d.val)) ORDER BY 1, 2, 3;
 
 -- ruleutils reverse parsing
-CREATE VIEW customers_us AS SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.address = 'US')-[IS customer_orders | customer_wishlists ]->(l IS orders | wishlists)-[ IS list_items]->(p IS products) COLUMNS (c.name AS customer_name, p.name AS product_name)) ORDER BY customer_name, product_name;
+-- The query in the view definition is intentionally complex to test one view with many
+-- features like label disjunction, lateral references, WHERE clauses in graph
+-- patterns.
+CREATE VIEW customers_us AS
+SELECT g.* FROM x1,
+                GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.address = 'US' AND c.customer_id = x1.a)
+                                          -[IS customer_orders | customer_wishlists ]->
+                                          (l IS orders | wishlists)-[ IS list_items]->(p IS products)
+                                    COLUMNS (c.name AS customer_name, p.name AS product_name, x1.a AS a)) g
+           ORDER BY customer_name, product_name;
 SELECT pg_get_viewdef('customers_us'::regclass);
 
 -- test view/graph nesting
-- 
2.34.1

