Subject: [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error

From: Bertrand Drouvot <[email-masked]>
Date: Wed, 22 Apr 2026 15:01:12 +0000

getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases
for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing
DROP PROPERTY GRAPH to hit the default case and error out with
"unsupported object class".

The bug only manifests when an event trigger is active, because that is what
calls these functions.

This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH
IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work
correctly when event triggers are present.

It also adds test cases that create an event trigger and then exercise DROP PROPERTY
GRAPH and DROP SCHEMA CASCADE with property graphs.

Author: Bertrand Drouvot <[email-masked]>
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 36 +++++++
 .../regress/sql/create_property_graph.sql     | 36 +++++++
 3 files changed, 165 insertions(+)
  54.5% src/backend/catalog/
  24.2% src/test/regress/expected/
  21.1% src/test/regress/sql/

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c1862809577..e2d6d8f71f6 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "policy");
 			break;
 
+		case PropgraphElementLabelRelationId:
+			appendStringInfoString(&buffer, "property graph element label");
+			break;
+
 		case PropgraphElementRelationId:
 			appendStringInfoString(&buffer, "property graph element");
 			break;
 
+		case PropgraphLabelPropertyRelationId:
+			appendStringInfoString(&buffer, "property graph label property");
+			break;
+
 		case PropgraphLabelRelationId:
 			appendStringInfoString(&buffer, "property graph label");
 			break;
@@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphElementLabelRelationId:
+			{
+				Relation	ellabelDesc;
+				ScanKeyData skey[1];
+				SysScanDesc ellabelscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_element_label pgelform;
+				ObjectAddress oa;
+
+				ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_element_label_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				ellabelscan = systable_beginscan(ellabelDesc,
+												 PropgraphElementLabelObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(ellabelscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for element label %u",
+							 object->objectId);
+
+					systable_endscan(ellabelscan);
+					table_close(ellabelDesc, AccessShareLock);
+					break;
+				}
+
+				pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
+
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(ellabelscan);
+				table_close(ellabelDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphElementRelationId:
 			{
 				HeapTuple	tup;
@@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object,
 				break;
 			}
 
+		case PropgraphLabelPropertyRelationId:
+			{
+				Relation	lblpropDesc;
+				ScanKeyData skey[1];
+				SysScanDesc lblpropscan;
+				HeapTuple	tup;
+				Form_pg_propgraph_label_property plpform;
+				ObjectAddress oa;
+
+				lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
+										 AccessShareLock);
+				ScanKeyInit(&skey[0],
+							Anum_pg_propgraph_label_property_oid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(object->objectId));
+
+				lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId,
+												 true, NULL, 1, skey);
+
+				tup = systable_getnext(lblpropscan);
+				if (!HeapTupleIsValid(tup))
+				{
+					if (!missing_ok)
+						elog(ERROR, "could not find tuple for label property %u",
+							 object->objectId);
+
+					systable_endscan(lblpropscan);
+					table_close(lblpropDesc, AccessShareLock);
+					break;
+				}
+
+				plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
+
+				ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
+				appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
+																	   objargs, false));
+
+				systable_endscan(lblpropscan);
+				table_close(lblpropDesc, AccessShareLock);
+				break;
+			}
+
 		case PropgraphLabelRelationId:
 			{
 				HeapTuple	tup;
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index bc9a596ec89..942a1294b15 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 NOTICE:  relation "g1" does not exist, skipping
 DROP PROPERTY GRAPH IF EXISTS g1;
 NOTICE:  property graph "g1" does not exist, skipping
+-- Test DROP PROPERTY GRAPH with dependency resolution
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE dpg_t1, dpg_t2;
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table dpg_schema.t
+drop cascades to property graph dpg_schema.g
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
 DROP ROLE regress_graph_user1, regress_graph_user2;
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..857098dadc8 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a));  -- error
 ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2;
 DROP PROPERTY GRAPH IF EXISTS g1;
 
+
+-- Test DROP PROPERTY GRAPH with dependency resolution
+
+RESET search_path;
+CREATE FUNCTION dpg_evt_func() RETURNS event_trigger
+LANGUAGE plpgsql AS $$
+BEGIN END;
+$$;
+
+CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func();
+
+CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text);
+CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int);
+CREATE PROPERTY GRAPH dpg_test
+    VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name))
+    EDGE TABLES (dpg_t2 KEY (id)
+        SOURCE KEY (src) REFERENCES dpg_t1 (id)
+        DESTINATION KEY (dst) REFERENCES dpg_t1 (id)
+        LABEL knows);
+DROP PROPERTY GRAPH dpg_test;
+
+-- table survives graph drop
+SELECT COUNT(*) FROM dpg_t1;
+DROP TABLE dpg_t1, dpg_t2;
+
+-- Test DROP SCHEMA CASCADE with property graphs inside
+CREATE SCHEMA dpg_schema;
+SET search_path = dpg_schema;
+CREATE TABLE t (id int PRIMARY KEY);
+CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id));
+RESET search_path;
+DROP SCHEMA dpg_schema CASCADE;
+
+DROP EVENT TRIGGER dpg_evt;
+DROP FUNCTION dpg_evt_func;
+
 DROP ROLE regress_graph_user1, regress_graph_user2;
 
 -- leave remaining objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1

--s/7v445LwpBnK/Gl--