From e2f8e1562a8e863fc896442175892e6a011a593b Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Date: Sun, 17 May 2026 12:21:13 +0530
Subject: [PATCH v20260517 5/5] Record dependencies on graph labels and
 properties

A view definition with GRAPH_TABLE depends upon the property graph it
references as well as the properties and labels referenced in it. We
recorded the dependency on the property graph, but did not record
dependency on labels and properties. This allowed properties or labels
referenced by a view to be dropped resulting in a cache lookup error
when such a view was accessed. Fix this bug by handling GraphPropertyRef
and GraphLabelRef in find_expr_references_walker(). The dependency on
the data type of property is not needed to be recorded separately as it
is recorded indirectly via dependency on the property graph property
itself.

Please note that a property or a label associated with individual
elements can still be dropped as long as there are other elements which
are associated with that property or label since they do not lead to
dropping the property or the label from the property graph altogether.

Reported-by: Man Zeng <zengman@halodbtech.com>
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Author: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reviewed by: Junwang Zhao <zhjwpku@gmail.com>
Discussion: https://postgr.es/m/tencent_43D9888041FA4FDE498C7BF1@qq.com
---
 src/backend/catalog/dependency.c          | 19 ++++++++++++
 src/test/regress/expected/graph_table.out | 37 +++++++++++++++++------
 src/test/regress/sql/graph_table.sql      | 14 +++++++--
 3 files changed, 59 insertions(+), 11 deletions(-)

diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index fdb8e67e1f5..c54774b3275 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -2165,6 +2165,25 @@ find_expr_references_walker(Node *node,
 		add_object_address(TypeRelationId, rowexpr->row_typeid, 0,
 						   context->addrs);
 	}
+	else if (IsA(node, GraphLabelRef))
+	{
+		GraphLabelRef *glr = (GraphLabelRef *) node;
+
+		/* GRAPH_TABLE label reference depends on the property graph label */
+		add_object_address(PropgraphLabelRelationId, glr->labelid, 0,
+						   context->addrs);
+	}
+	else if (IsA(node, GraphPropertyRef))
+	{
+		GraphPropertyRef *gpr = (GraphPropertyRef *) node;
+
+		/*
+		 * GRAPH_TABLE property reference depends on the property graph
+		 * property
+		 */
+		add_object_address(PropgraphPropertyRelationId, gpr->propid, 0,
+						   context->addrs);
+	}
 	else if (IsA(node, RowCompareExpr))
 	{
 		RowCompareExpr *rcexpr = (RowCompareExpr *) node;
diff --git a/src/test/regress/expected/graph_table.out b/src/test/regress/expected/graph_table.out
index e8d49fd5cd4..a5f9f0ac90a 100644
--- a/src/test/regress/expected/graph_table.out
+++ b/src/test/regress/expected/graph_table.out
@@ -929,7 +929,7 @@ SELECT * FROM GRAPH_TABLE (g4 MATCH (s WHERE s.id = 3)-[e]-(d) COLUMNS (s.val, e
   30 | 300 |  10
 (2 rows)
 
--- ruleutils reverse parsing
+-- GRAPH_TABLE in views
 -- 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.
@@ -938,16 +938,35 @@ 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
+                                    COLUMNS (c.name AS customer_name, p.name AS product_name, p.price, x1.a AS a)) g
            ORDER BY customer_name, product_name;
+-- Dropping properties or labels used by a view is not allowed
+-- If these DDLs succeed, the pg_get_viewdef call below will throw cache lookup
+-- error.
+ALTER PROPERTY GRAPH myshop ALTER VERTEX TABLE orders DROP LABEL orders; -- error
+ERROR:  cannot drop label orders of property graph myshop because other objects depend on it
+DETAIL:  view customers_us depends on label orders of property graph myshop
+HINT:  Use DROP ... CASCADE to drop the dependent objects too.
+ALTER PROPERTY GRAPH myshop ALTER VERTEX TABLE customers
+    ALTER LABEL customers DROP PROPERTIES (address);  -- error
+ERROR:  cannot drop property address of property graph myshop because other objects depend on it
+DETAIL:  view customers_us depends on property address of property graph myshop
+HINT:  Use DROP ... CASCADE to drop the dependent objects too.
+ALTER PROPERTY GRAPH myshop ALTER VERTEX TABLE products
+    ALTER LABEL products DROP PROPERTIES (price);  -- error
+ERROR:  cannot drop property price of property graph myshop because other objects depend on it
+DETAIL:  view customers_us depends on property price of property graph myshop
+HINT:  Use DROP ... CASCADE to drop the dependent objects too.
+-- ruleutils reverse parsing
 SELECT pg_get_viewdef('customers_us'::regclass);
-                                                                                                                                        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+
+                                                                                                                                                 pg_get_viewdef                                                                                                                                                 
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+  SELECT g.customer_name,                                                                                                                                                                                                                                                                                      +
+     g.product_name,                                                                                                                                                                                                                                                                                           +
+     g.price,                                                                                                                                                                                                                                                                                                  +
+     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, p.price AS price, x1.a AS a)) g+
    ORDER BY g.customer_name, g.product_name;
 (1 row)
 
diff --git a/src/test/regress/sql/graph_table.sql b/src/test/regress/sql/graph_table.sql
index e761f09e057..80576b2f9f4 100644
--- a/src/test/regress/sql/graph_table.sql
+++ b/src/test/regress/sql/graph_table.sql
@@ -525,7 +525,8 @@ SELECT * FROM GRAPH_TABLE (g4 MATCH (s IS ptnv)-[e IS ptne]->(d IS ptnv) COLUMNS
 SELECT * FROM GRAPH_TABLE (g4 MATCH (s)-[e]-(d) WHERE s.id = 3 COLUMNS (s.val, e.val, d.val)) ORDER BY 1, 2, 3;
 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
+-- GRAPH_TABLE in views
+
 -- 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.
@@ -534,8 +535,17 @@ 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
+                                    COLUMNS (c.name AS customer_name, p.name AS product_name, p.price, x1.a AS a)) g
            ORDER BY customer_name, product_name;
+-- Dropping properties or labels used by a view is not allowed
+-- If these DDLs succeed, the pg_get_viewdef call below will throw cache lookup
+-- error.
+ALTER PROPERTY GRAPH myshop ALTER VERTEX TABLE orders DROP LABEL orders; -- error
+ALTER PROPERTY GRAPH myshop ALTER VERTEX TABLE customers
+    ALTER LABEL customers DROP PROPERTIES (address);  -- error
+ALTER PROPERTY GRAPH myshop ALTER VERTEX TABLE products
+    ALTER LABEL products DROP PROPERTIES (price);  -- error
+-- ruleutils reverse parsing
 SELECT pg_get_viewdef('customers_us'::regclass);
 
 -- test view/graph nesting
-- 
2.34.1

