agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH v28 1/5] Base implementation of subscripting mechanism
2399+ messages / 6 participants
[nested] [flat]

* [PATCH v28 1/5] Base implementation of subscripting mechanism
@ 2019-01-31 21:37  erthalion <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: erthalion @ 2019-01-31 21:37 UTC (permalink / raw)

Introduce all the required machinery for generalizing subscripting
operation for a different data types:

* subscripting handler procedure, to set up a relation between data type
and corresponding subscripting logic.

* subscripting routines, that help generalize a subscripting logic,
since it involves few stages, namely preparation (e.g. to figure out
required types), validation (to check the input and return meaningful
error message), fetch (executed when we extract a value using
subscripting), assign (executed when we update a data type with a new
value using subscripting). Without this it would be neccessary to
introduce more new fields to pg_type, which would be too invasive.

All ArrayRef related logic was removed and landed as a separate
subscripting implementation in the following patch from this series. The
rest of the code was rearranged, to e.g. store a type of assigned value
for an assign operation.

Reviewed-by: Tom Lane, Arthur Zakirov
---
 contrib/pg_stat_statements/pg_stat_statements.c |   1 +
 src/backend/catalog/heap.c                      |   6 +-
 src/backend/catalog/pg_type.c                   |  15 ++-
 src/backend/commands/typecmds.c                 |  77 +++++++++++--
 src/backend/executor/execExpr.c                 |  25 +----
 src/backend/executor/execExprInterp.c           | 124 +++------------------
 src/backend/nodes/copyfuncs.c                   |   2 +
 src/backend/nodes/equalfuncs.c                  |   2 +
 src/backend/nodes/outfuncs.c                    |   2 +
 src/backend/nodes/readfuncs.c                   |   2 +
 src/backend/parser/parse_expr.c                 |  54 +++++----
 src/backend/parser/parse_node.c                 | 141 ++++++------------------
 src/backend/parser/parse_target.c               |  88 ++++++++-------
 src/backend/utils/adt/ruleutils.c               |  21 ++--
 src/backend/utils/cache/lsyscache.c             |  23 ++++
 src/include/c.h                                 |   2 +
 src/include/catalog/pg_class.dat                |   2 +-
 src/include/catalog/pg_type.h                   |   9 +-
 src/include/executor/execExpr.h                 |  13 ++-
 src/include/nodes/primnodes.h                   |   6 +
 src/include/nodes/subscripting.h                |  42 +++++++
 src/include/parser/parse_node.h                 |   4 +-
 src/include/utils/lsyscache.h                   |   1 +
 23 files changed, 335 insertions(+), 327 deletions(-)
 create mode 100644 src/include/nodes/subscripting.h

diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 221b472..2ff18de 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -2612,6 +2612,7 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
 				JumbleExpr(jstate, (Node *) sbsref->reflowerindexpr);
 				JumbleExpr(jstate, (Node *) sbsref->refexpr);
 				JumbleExpr(jstate, (Node *) sbsref->refassgnexpr);
+				APP_JUMB(sbsref->refnestedfunc);
 			}
 			break;
 		case T_FuncExpr:
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index b7bcdd9..210c130 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1026,7 +1026,8 @@ AddNewRelationType(const char *typeName,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,  /* rowtypes never have a collation */
+				   InvalidOid);	/* typsubshandler - none */
 }
 
 /* --------------------------------
@@ -1307,7 +1308,8 @@ heap_create_with_catalog(const char *relname,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,  /* rowtypes never have a collation */
+				   0);	/* array implementation */
 
 		pfree(relarrayname);
 	}
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 2a51501..54f7ba5 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -118,6 +118,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
 	values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1);
 	values[Anum_pg_type_typndims - 1] = Int32GetDatum(0);
 	values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
+	values[Anum_pg_type_typsubshandler - 1] = ObjectIdGetDatum(InvalidOid);
 	nulls[Anum_pg_type_typdefaultbin - 1] = true;
 	nulls[Anum_pg_type_typdefault - 1] = true;
 	nulls[Anum_pg_type_typacl - 1] = true;
@@ -158,10 +159,10 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
 		GenerateTypeDependencies(typoid,
 								 (Form_pg_type) GETSTRUCT(tup),
 								 NULL,
-								 NULL,
 								 0,
 								 false,
 								 false,
+								 InvalidOid,
 								 false);
 
 	/* Post creation hook for new shell type */
@@ -219,7 +220,8 @@ TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,		/* Array dimensions for baseType */
 		   bool typeNotNull,
-		   Oid typeCollation)
+		   Oid typeCollation,
+		   Oid subscriptingHandlerProcedure)
 {
 	Relation	pg_type_desc;
 	Oid			typeObjectId;
@@ -371,6 +373,7 @@ TypeCreate(Oid newTypeOid,
 	values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod);
 	values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims);
 	values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(typeCollation);
+	values[Anum_pg_type_typsubshandler - 1] = ObjectIdGetDatum(subscriptingHandlerProcedure);
 
 	/*
 	 * initialize the default binary value for this type.  Check for nulls of
@@ -694,6 +697,14 @@ GenerateTypeDependencies(Oid typeObjectId,
 	/* Normal dependency on the default expression. */
 	if (defaultExpr)
 		recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
+
+	if (OidIsValid(typeForm->typsubshandler))
+	{
+		referenced.classId = ProcedureRelationId;
+		referenced.objectId = typeForm->typsubshandler;
+		referenced.objectSubId = 0;
+		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	}
 }
 
 /*
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 89887b8..a9ffefc 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -95,6 +95,7 @@ static Oid	findTypeSendFunction(List *procname, Oid typeOid);
 static Oid	findTypeTypmodinFunction(List *procname);
 static Oid	findTypeTypmodoutFunction(List *procname);
 static Oid	findTypeAnalyzeFunction(List *procname, Oid typeOid);
+static Oid	findTypeSubscriptingFunction(List *procname, Oid typeOid, bool parseFunc);
 static Oid	findRangeSubOpclass(List *opcname, Oid subtype);
 static Oid	findRangeCanonicalFunction(List *procname, Oid typeOid);
 static Oid	findRangeSubtypeDiffFunction(List *procname, Oid subtype);
@@ -126,6 +127,7 @@ DefineType(ParseState *pstate, List *names, List *parameters)
 	List	   *typmodinName = NIL;
 	List	   *typmodoutName = NIL;
 	List	   *analyzeName = NIL;
+	List	   *subscriptingParseName = NIL;
 	char		category = TYPCATEGORY_USER;
 	bool		preferred = false;
 	char		delimiter = DEFAULT_TYPDELIM;
@@ -144,6 +146,7 @@ DefineType(ParseState *pstate, List *names, List *parameters)
 	DefElem    *typmodinNameEl = NULL;
 	DefElem    *typmodoutNameEl = NULL;
 	DefElem    *analyzeNameEl = NULL;
+	DefElem    *subscriptingParseNameEl = NULL;
 	DefElem    *categoryEl = NULL;
 	DefElem    *preferredEl = NULL;
 	DefElem    *delimiterEl = NULL;
@@ -166,6 +169,7 @@ DefineType(ParseState *pstate, List *names, List *parameters)
 	Oid			resulttype;
 	ListCell   *pl;
 	ObjectAddress address;
+	Oid			subscriptingParseOid = InvalidOid;
 
 	/*
 	 * As of Postgres 8.4, we require superuser privilege to create a base
@@ -265,6 +269,8 @@ DefineType(ParseState *pstate, List *names, List *parameters)
 		else if (strcmp(defel->defname, "analyze") == 0 ||
 				 strcmp(defel->defname, "analyse") == 0)
 			defelp = &analyzeNameEl;
+		else if (strcmp(defel->defname, "subscripting_handler") == 0)
+			defelp = &subscriptingParseNameEl;
 		else if (strcmp(defel->defname, "category") == 0)
 			defelp = &categoryEl;
 		else if (strcmp(defel->defname, "preferred") == 0)
@@ -335,6 +341,8 @@ DefineType(ParseState *pstate, List *names, List *parameters)
 		typmodoutName = defGetQualifiedName(typmodoutNameEl);
 	if (analyzeNameEl)
 		analyzeName = defGetQualifiedName(analyzeNameEl);
+	if (subscriptingParseNameEl)
+		subscriptingParseName = defGetQualifiedName(subscriptingParseNameEl);
 	if (categoryEl)
 	{
 		char	   *p = defGetString(categoryEl);
@@ -516,6 +524,10 @@ DefineType(ParseState *pstate, List *names, List *parameters)
 	if (analyzeName)
 		analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
 
+	if (subscriptingParseName)
+		subscriptingParseOid = findTypeSubscriptingFunction(subscriptingParseName,
+															typoid, true);
+
 	/*
 	 * Check permissions on functions.  We choose to require the creator/owner
 	 * of a type to also own the underlying functions.  Since creating a type
@@ -635,7 +647,8 @@ DefineType(ParseState *pstate, List *names, List *parameters)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array Dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   collation);	/* type's collation */
+				   collation,	/* type's collation */
+				   subscriptingParseOid);	/* subscripting procedure */
 	Assert(typoid == address.objectId);
 
 	/*
@@ -676,7 +689,8 @@ DefineType(ParseState *pstate, List *names, List *parameters)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   collation);		/* type's collation */
+			   collation,		/* type's collation */
+			   0);
 
 	pfree(array_type);
 
@@ -739,6 +753,7 @@ DefineDomain(CreateDomainStmt *stmt)
 	Oid			receiveProcedure;
 	Oid			sendProcedure;
 	Oid			analyzeProcedure;
+	Oid			subscriptingHandlerProcedure;
 	bool		byValue;
 	char		category;
 	char		delimiter;
@@ -866,6 +881,9 @@ DefineDomain(CreateDomainStmt *stmt)
 	/* Analysis function */
 	analyzeProcedure = baseType->typanalyze;
 
+	/* Subscripting functions */
+	subscriptingHandlerProcedure = baseType->typsubshandler;
+
 	/* Inherited default value */
 	datum = SysCacheGetAttr(TYPEOID, typeTup,
 							Anum_pg_type_typdefault, &isnull);
@@ -1071,7 +1089,8 @@ DefineDomain(CreateDomainStmt *stmt)
 				   basetypeMod, /* typeMod value */
 				   typNDims,	/* Array dimensions for base type */
 				   typNotNull,	/* Type NOT NULL */
-				   domaincoll); /* type's collation */
+				   domaincoll,  /* type's collation */
+				   subscriptingHandlerProcedure);	/* subscripting procedure */
 
 	/*
 	 * Create the array type that goes with it.
@@ -1111,7 +1130,8 @@ DefineDomain(CreateDomainStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   domaincoll);		/* type's collation */
+			   domaincoll,		/* type's collation */
+			   0); /* array subscripting implementation */
 
 	pfree(domainArrayName);
 
@@ -1226,7 +1246,8 @@ DefineEnum(CreateEnumStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation */
+				   InvalidOid,  /* type's collation */
+				   InvalidOid);	/* typsubshandler - none */
 
 	/* Enter the enum's values into pg_enum */
 	EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
@@ -1266,7 +1287,8 @@ DefineEnum(CreateEnumStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* type's collation */
+			   InvalidOid,		/* type's collation */
+			   0);	/* array subscripting implementation */
 
 	pfree(enumArrayName);
 
@@ -1554,7 +1576,8 @@ DefineRange(CreateRangeStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation (ranges never have one) */
+				   InvalidOid,  /* type's collation (ranges never have one) */
+				   InvalidOid);	/* typsubshandler - none */
 	Assert(typoid == address.objectId);
 
 	/* Create the entry in pg_range */
@@ -1596,7 +1619,8 @@ DefineRange(CreateRangeStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* typcollation */
+			   InvalidOid,		/* typcollation */
+			   0);	/* array subscripting implementation */
 
 	pfree(rangeArrayName);
 
@@ -1940,6 +1964,43 @@ findTypeAnalyzeFunction(List *procname, Oid typeOid)
 	return procOid;
 }
 
+static Oid
+findTypeSubscriptingFunction(List *procname, Oid typeOid, bool parseFunc)
+{
+	Oid			argList[2];
+	Oid			procOid;
+	int			nargs;
+
+	if (parseFunc)
+	{
+		/*
+		 * Subscripting function parse always take two INTERNAL argument and
+		 * return INTERNAL.
+		 */
+		argList[0] = INTERNALOID;
+		nargs = 1;
+	}
+	else
+	{
+		/*
+		 * Subscripting functions fetch/assign always take one typeOid
+		 * argument, one INTERNAL argument and return typeOid.
+		 */
+		argList[0] = typeOid;
+		argList[1] = INTERNALOID;
+		nargs = 2;
+	}
+
+	procOid = LookupFuncName(procname, nargs, argList, true);
+	if (!OidIsValid(procOid))
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_FUNCTION),
+				 errmsg("function %s does not exist",
+						func_signature_string(procname, nargs, NIL, argList))));
+
+	return procOid;
+}
+
 /*
  * Find suitable support functions and opclasses for a range type.
  */
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 7e48644..854b2e4 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -2544,18 +2544,16 @@ ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref,
 {
 	bool		isAssignment = (sbsref->refassgnexpr != NULL);
 	SubscriptingRefState *sbsrefstate = palloc0(sizeof(SubscriptingRefState));
-	List	   *adjust_jumps = NIL;
-	ListCell   *lc;
-	int			i;
+	List				 *adjust_jumps = NIL;
+	ListCell   			 *lc;
+	int		   			  i;
+	RegProcedure		  typsubshandler = get_typsubsprocs(sbsref->refcontainertype);
 
 	/* Fill constant fields of SubscriptingRefState */
 	sbsrefstate->isassignment = isAssignment;
 	sbsrefstate->refelemtype = sbsref->refelemtype;
 	sbsrefstate->refattrlength = get_typlen(sbsref->refcontainertype);
-	get_typlenbyvalalign(sbsref->refelemtype,
-						 &sbsrefstate->refelemlength,
-						 &sbsrefstate->refelembyval,
-						 &sbsrefstate->refelemalign);
+	sbsrefstate->sbsroutines = (SubscriptRoutines *) OidFunctionCall0(typsubshandler);
 
 	/*
 	 * Evaluate array input.  It's safe to do so into resv/resnull, because we
@@ -2579,19 +2577,6 @@ ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref,
 								   state->steps_len - 1);
 	}
 
-	/* Verify subscript list lengths are within limit */
-	if (list_length(sbsref->refupperindexpr) > MAXDIM)
-		ereport(ERROR,
-				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
-				 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
-						list_length(sbsref->refupperindexpr), MAXDIM)));
-
-	if (list_length(sbsref->reflowerindexpr) > MAXDIM)
-		ereport(ERROR,
-				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
-				 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
-						list_length(sbsref->reflowerindexpr), MAXDIM)));
-
 	/* Evaluate upper subscripts */
 	i = 0;
 	foreach(lc, sbsref->refupperindexpr)
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 0cd6f65..e0d2f8f 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3160,8 +3160,8 @@ bool
 ExecEvalSubscriptingRef(ExprState *state, ExprEvalStep *op)
 {
 	SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state;
-	int		   *indexes;
-	int			off;
+	Datum				 *indexes;
+	int					 off;
 
 	/* If any index expr yields NULL, result is NULL or error */
 	if (sbsrefstate->subscriptnull)
@@ -3181,7 +3181,7 @@ ExecEvalSubscriptingRef(ExprState *state, ExprEvalStep *op)
 		indexes = sbsrefstate->lowerindex;
 	off = op->d.sbsref_subscript.off;
 
-	indexes[off] = DatumGetInt32(sbsrefstate->subscriptvalue);
+	indexes[off] = sbsrefstate->subscriptvalue;
 
 	return true;
 }
@@ -3195,36 +3195,14 @@ void
 ExecEvalSubscriptingRefFetch(ExprState *state, ExprEvalStep *op)
 {
 	SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
+	SubscriptRoutines	 *sbsroutines = sbsrefstate->sbsroutines;
 
 	/* Should not get here if source container (or any subscript) is null */
 	Assert(!(*op->resnull));
 
-	if (sbsrefstate->numlower == 0)
-	{
-		/* Scalar case */
-		*op->resvalue = array_get_element(*op->resvalue,
-										  sbsrefstate->numupper,
-										  sbsrefstate->upperindex,
-										  sbsrefstate->refattrlength,
-										  sbsrefstate->refelemlength,
-										  sbsrefstate->refelembyval,
-										  sbsrefstate->refelemalign,
-										  op->resnull);
-	}
-	else
-	{
-		/* Slice case */
-		*op->resvalue = array_get_slice(*op->resvalue,
-										sbsrefstate->numupper,
-										sbsrefstate->upperindex,
-										sbsrefstate->lowerindex,
-										sbsrefstate->upperprovided,
-										sbsrefstate->lowerprovided,
-										sbsrefstate->refattrlength,
-										sbsrefstate->refelemlength,
-										sbsrefstate->refelembyval,
-										sbsrefstate->refelemalign);
-	}
+
+	*op->resvalue = sbsroutines->fetch(*op->resvalue, sbsrefstate);
+	*op->resnull = sbsrefstate->resnull;
 }
 
 /*
@@ -3237,40 +3215,20 @@ void
 ExecEvalSubscriptingRefOld(ExprState *state, ExprEvalStep *op)
 {
 	SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
+	SubscriptRoutines	 *sbsroutines = sbsrefstate->sbsroutines;
 
 	if (*op->resnull)
 	{
-		/* whole array is null, so any element or slice is too */
+		/* whole container is null, so any element or slice is too */
 		sbsrefstate->prevvalue = (Datum) 0;
 		sbsrefstate->prevnull = true;
 	}
-	else if (sbsrefstate->numlower == 0)
-	{
-		/* Scalar case */
-		sbsrefstate->prevvalue = array_get_element(*op->resvalue,
-												   sbsrefstate->numupper,
-												   sbsrefstate->upperindex,
-												   sbsrefstate->refattrlength,
-												   sbsrefstate->refelemlength,
-												   sbsrefstate->refelembyval,
-												   sbsrefstate->refelemalign,
-												   &sbsrefstate->prevnull);
-	}
 	else
 	{
-		/* Slice case */
-		/* this is currently unreachable */
-		sbsrefstate->prevvalue = array_get_slice(*op->resvalue,
-												 sbsrefstate->numupper,
-												 sbsrefstate->upperindex,
-												 sbsrefstate->lowerindex,
-												 sbsrefstate->upperprovided,
-												 sbsrefstate->lowerprovided,
-												 sbsrefstate->refattrlength,
-												 sbsrefstate->refelemlength,
-												 sbsrefstate->refelembyval,
-												 sbsrefstate->refelemalign);
-		sbsrefstate->prevnull = false;
+		sbsrefstate->prevvalue = sbsroutines->fetch(*op->resvalue, sbsrefstate);
+
+		if (sbsrefstate->numlower != 0)
+			sbsrefstate->prevnull = false;
 	}
 }
 
@@ -3284,59 +3242,11 @@ void
 ExecEvalSubscriptingRefAssign(ExprState *state, ExprEvalStep *op)
 {
 	SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state;
+	SubscriptRoutines	 *sbsroutines = sbsrefstate->sbsroutines;
 
-	/*
-	 * For an assignment to a fixed-length container type, both the original
-	 * container and the value to be assigned into it must be non-NULL, else
-	 * we punt and return the original container.
-	 */
-	if (sbsrefstate->refattrlength > 0)
-	{
-		if (*op->resnull || sbsrefstate->replacenull)
-			return;
-	}
-
-	/*
-	 * For assignment to varlena arrays, we handle a NULL original array by
-	 * substituting an empty (zero-dimensional) array; insertion of the new
-	 * element will result in a singleton array value.  It does not matter
-	 * whether the new element is NULL.
-	 */
-	if (*op->resnull)
-	{
-		*op->resvalue = PointerGetDatum(construct_empty_array(sbsrefstate->refelemtype));
-		*op->resnull = false;
-	}
-
-	if (sbsrefstate->numlower == 0)
-	{
-		/* Scalar case */
-		*op->resvalue = array_set_element(*op->resvalue,
-										  sbsrefstate->numupper,
-										  sbsrefstate->upperindex,
-										  sbsrefstate->replacevalue,
-										  sbsrefstate->replacenull,
-										  sbsrefstate->refattrlength,
-										  sbsrefstate->refelemlength,
-										  sbsrefstate->refelembyval,
-										  sbsrefstate->refelemalign);
-	}
-	else
-	{
-		/* Slice case */
-		*op->resvalue = array_set_slice(*op->resvalue,
-										sbsrefstate->numupper,
-										sbsrefstate->upperindex,
-										sbsrefstate->lowerindex,
-										sbsrefstate->upperprovided,
-										sbsrefstate->lowerprovided,
-										sbsrefstate->replacevalue,
-										sbsrefstate->replacenull,
-										sbsrefstate->refattrlength,
-										sbsrefstate->refelemlength,
-										sbsrefstate->refelembyval,
-										sbsrefstate->refelemalign);
-	}
+	sbsrefstate->resnull = *op->resnull;
+	*op->resvalue = sbsroutines->assign(*op->resvalue, sbsrefstate);
+	*op->resnull = sbsrefstate->resnull;
 }
 
 /*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 3432bb9..1011d02 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1505,8 +1505,10 @@ _copySubscriptingRef(const SubscriptingRef *from)
 
 	COPY_SCALAR_FIELD(refcontainertype);
 	COPY_SCALAR_FIELD(refelemtype);
+	COPY_SCALAR_FIELD(refassgntype);
 	COPY_SCALAR_FIELD(reftypmod);
 	COPY_SCALAR_FIELD(refcollid);
+	COPY_SCALAR_FIELD(refnestedfunc);
 	COPY_NODE_FIELD(refupperindexpr);
 	COPY_NODE_FIELD(reflowerindexpr);
 	COPY_NODE_FIELD(refexpr);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 18cb014..6cfa426 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -270,8 +270,10 @@ _equalSubscriptingRef(const SubscriptingRef *a, const SubscriptingRef *b)
 {
 	COMPARE_SCALAR_FIELD(refcontainertype);
 	COMPARE_SCALAR_FIELD(refelemtype);
+	COMPARE_SCALAR_FIELD(refassgntype);
 	COMPARE_SCALAR_FIELD(reftypmod);
 	COMPARE_SCALAR_FIELD(refcollid);
+	COMPARE_SCALAR_FIELD(refnestedfunc);
 	COMPARE_NODE_FIELD(refupperindexpr);
 	COMPARE_NODE_FIELD(reflowerindexpr);
 	COMPARE_NODE_FIELD(refexpr);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index b0dcd02..93dc7ae 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1169,8 +1169,10 @@ _outSubscriptingRef(StringInfo str, const SubscriptingRef *node)
 
 	WRITE_OID_FIELD(refcontainertype);
 	WRITE_OID_FIELD(refelemtype);
+	WRITE_OID_FIELD(refassgntype);
 	WRITE_INT_FIELD(reftypmod);
 	WRITE_OID_FIELD(refcollid);
+	WRITE_OID_FIELD(refnestedfunc);
 	WRITE_NODE_FIELD(refupperindexpr);
 	WRITE_NODE_FIELD(reflowerindexpr);
 	WRITE_NODE_FIELD(refexpr);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 764e3bb..130eeb3 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -668,8 +668,10 @@ _readSubscriptingRef(void)
 
 	READ_OID_FIELD(refcontainertype);
 	READ_OID_FIELD(refelemtype);
+	READ_OID_FIELD(refassgntype);
 	READ_INT_FIELD(reftypmod);
 	READ_OID_FIELD(refcollid);
+	READ_OID_FIELD(refnestedfunc);
 	READ_NODE_FIELD(refupperindexpr);
 	READ_NODE_FIELD(reflowerindexpr);
 	READ_NODE_FIELD(refexpr);
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 76f3dd7..bd6eaed 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -433,11 +433,13 @@ unknown_attribute(ParseState *pstate, Node *relref, const char *attname,
 static Node *
 transformIndirection(ParseState *pstate, A_Indirection *ind)
 {
-	Node	   *last_srf = pstate->p_last_srf;
-	Node	   *result = transformExprRecurse(pstate, ind->arg);
-	List	   *subscripts = NIL;
-	int			location = exprLocation(result);
-	ListCell   *i;
+	Node			  *last_srf = pstate->p_last_srf;
+	Node			  *result = transformExprRecurse(pstate, ind->arg);
+	SubscriptRoutines *sbsroutines;
+	SubscriptingRef   *sbsref;
+	List	          *subscripts = NIL;
+	int				  location = exprLocation(result);
+	ListCell		  *i;
 
 	/*
 	 * We have to split any field-selection operations apart from
@@ -465,13 +467,20 @@ transformIndirection(ParseState *pstate, A_Indirection *ind)
 
 			/* process subscripts before this field selection */
 			if (subscripts)
-				result = (Node *) transformContainerSubscripts(pstate,
-															   result,
-															   exprType(result),
-															   InvalidOid,
-															   exprTypmod(result),
-															   subscripts,
-															   NULL);
+			{
+				sbsref = transformContainerSubscripts(pstate,
+													  result,
+													  exprType(result),
+													  InvalidOid,
+													  exprTypmod(result),
+													  subscripts,
+													  NULL);
+
+				sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype);
+				sbsref = sbsroutines->prepare(false, sbsref);
+				sbsroutines->validate(false, sbsref, pstate);
+				result = (Node *) sbsref;
+			}
 			subscripts = NIL;
 
 			newresult = ParseFuncOrColumn(pstate,
@@ -488,13 +497,20 @@ transformIndirection(ParseState *pstate, A_Indirection *ind)
 	}
 	/* process trailing subscripts, if any */
 	if (subscripts)
-		result = (Node *) transformContainerSubscripts(pstate,
-													   result,
-													   exprType(result),
-													   InvalidOid,
-													   exprTypmod(result),
-													   subscripts,
-													   NULL);
+	{
+		sbsref = transformContainerSubscripts(pstate,
+											  result,
+											  exprType(result),
+											  InvalidOid,
+											  exprTypmod(result),
+											  subscripts,
+											  NULL);
+
+		sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype);
+		sbsref = sbsroutines->prepare(false, sbsref);
+		sbsroutines->validate(false, sbsref, pstate);
+		result = (Node *) sbsref;
+	}
 
 	return result;
 }
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 1baf7ef..ba2b934 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -206,21 +206,12 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, int location)
  * transformContainerType()
  *		Identify the types involved in a subscripting operation for container
  *
- *
- * On entry, containerType/containerTypmod identify the type of the input value
- * to be subscripted (which could be a domain type).  These are modified if
- * necessary to identify the actual container type and typmod, and the
- * container's element type is returned.  An error is thrown if the input isn't
- * an array type.
+ * On entry, containerType/containerTypmod  are modified if necessary to
+ * identify the actual container type and typmod.
  */
-Oid
+void
 transformContainerType(Oid *containerType, int32 *containerTypmod)
 {
-	Oid			origContainerType = *containerType;
-	Oid			elementType;
-	HeapTuple	type_tuple_container;
-	Form_pg_type type_struct_container;
-
 	/*
 	 * If the input is a domain, smash to base type, and extract the actual
 	 * typmod to be applied to the base type. Subscripting a domain is an
@@ -241,25 +232,6 @@ transformContainerType(Oid *containerType, int32 *containerTypmod)
 		*containerType = INT2ARRAYOID;
 	else if (*containerType == OIDVECTOROID)
 		*containerType = OIDARRAYOID;
-
-	/* Get the type tuple for the container */
-	type_tuple_container = SearchSysCache1(TYPEOID, ObjectIdGetDatum(*containerType));
-	if (!HeapTupleIsValid(type_tuple_container))
-		elog(ERROR, "cache lookup failed for type %u", *containerType);
-	type_struct_container = (Form_pg_type) GETSTRUCT(type_tuple_container);
-
-	/* needn't check typisdefined since this will fail anyway */
-
-	elementType = type_struct_container->typelem;
-	if (elementType == InvalidOid)
-		ereport(ERROR,
-				(errcode(ERRCODE_DATATYPE_MISMATCH),
-				 errmsg("cannot subscript type %s because it is not an array",
-						format_type_be(origContainerType))));
-
-	ReleaseSysCache(type_tuple_container);
-
-	return elementType;
 }
 
 /*
@@ -276,10 +248,15 @@ transformContainerType(Oid *containerType, int32 *containerTypmod)
  * container. We produce an expression that represents the new container value
  * with the source data inserted into the right part of the container.
  *
- * For both cases, if the source container is of a domain-over-array type,
- * the result is of the base array type or its element type; essentially,
- * we must fold a domain to its base type before applying subscripting.
- * (Note that int2vector and oidvector are treated as domains here.)
+ * For both cases, this function contains only general subscripting logic while
+ * type-specific logic (e.g. type verifications and coersion) is placen in
+ * separate procedure indicated by typsubshandler. There is only one exception
+ * for now about domain-over-container, if the source container is of a
+ * domain-over-container type, the result is of the base container type or its
+ * element type; essentially, we must fold a domain to its base type before
+ * applying subscripting. (Note that int2vector and oidvector are treated as
+ * domains here.) An error will appear in case if current container type
+ * doesn't have a subscripting procedure.
  *
  * pstate			Parse state
  * containerBase	Already-transformed expression for the container as a whole
@@ -306,16 +283,12 @@ transformContainerSubscripts(ParseState *pstate,
 	bool		isSlice = false;
 	List	   *upperIndexpr = NIL;
 	List	   *lowerIndexpr = NIL;
+	List	   *indexprSlice = NIL;
 	ListCell   *idx;
 	SubscriptingRef *sbsref;
 
-	/*
-	 * Caller may or may not have bothered to determine elementType.  Note
-	 * that if the caller did do so, containerType/containerTypMod must be as
-	 * modified by transformContainerType, ie, smash domain to base type.
-	 */
-	if (!OidIsValid(elementType))
-		elementType = transformContainerType(&containerType, &containerTypMod);
+	/* Identify the actual container type and element type involved */
+	transformContainerType(&containerType, &containerTypMod);
 
 	/*
 	 * A list containing only simple subscripts refers to a single container
@@ -349,29 +322,6 @@ transformContainerSubscripts(ParseState *pstate,
 			if (ai->lidx)
 			{
 				subexpr = transformExpr(pstate, ai->lidx, pstate->p_expr_kind);
-				/* If it's not int4 already, try to coerce */
-				subexpr = coerce_to_target_type(pstate,
-												subexpr, exprType(subexpr),
-												INT4OID, -1,
-												COERCION_ASSIGNMENT,
-												COERCE_IMPLICIT_CAST,
-												-1);
-				if (subexpr == NULL)
-					ereport(ERROR,
-							(errcode(ERRCODE_DATATYPE_MISMATCH),
-							 errmsg("array subscript must have type integer"),
-							 parser_errposition(pstate, exprLocation(ai->lidx))));
-			}
-			else if (!ai->is_slice)
-			{
-				/* Make a constant 1 */
-				subexpr = (Node *) makeConst(INT4OID,
-											 -1,
-											 InvalidOid,
-											 sizeof(int32),
-											 Int32GetDatum(1),
-											 false,
-											 true); /* pass by value */
 			}
 			else
 			{
@@ -379,64 +329,24 @@ transformContainerSubscripts(ParseState *pstate,
 				subexpr = NULL;
 			}
 			lowerIndexpr = lappend(lowerIndexpr, subexpr);
+			indexprSlice = lappend(indexprSlice, ai);
 		}
 		else
 			Assert(ai->lidx == NULL && !ai->is_slice);
 
 		if (ai->uidx)
-		{
 			subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
-			/* If it's not int4 already, try to coerce */
-			subexpr = coerce_to_target_type(pstate,
-											subexpr, exprType(subexpr),
-											INT4OID, -1,
-											COERCION_ASSIGNMENT,
-											COERCE_IMPLICIT_CAST,
-											-1);
-			if (subexpr == NULL)
-				ereport(ERROR,
-						(errcode(ERRCODE_DATATYPE_MISMATCH),
-						 errmsg("array subscript must have type integer"),
-						 parser_errposition(pstate, exprLocation(ai->uidx))));
-		}
 		else
 		{
 			/* Slice with omitted upper bound, put NULL into the list */
 			Assert(isSlice && ai->is_slice);
 			subexpr = NULL;
 		}
+		subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
 		upperIndexpr = lappend(upperIndexpr, subexpr);
 	}
 
 	/*
-	 * If doing an array store, coerce the source value to the right type.
-	 * (This should agree with the coercion done by transformAssignedExpr.)
-	 */
-	if (assignFrom != NULL)
-	{
-		Oid			typesource = exprType(assignFrom);
-		Oid			typeneeded = isSlice ? containerType : elementType;
-		Node	   *newFrom;
-
-		newFrom = coerce_to_target_type(pstate,
-										assignFrom, typesource,
-										typeneeded, containerTypMod,
-										COERCION_ASSIGNMENT,
-										COERCE_IMPLICIT_CAST,
-										-1);
-		if (newFrom == NULL)
-			ereport(ERROR,
-					(errcode(ERRCODE_DATATYPE_MISMATCH),
-					 errmsg("array assignment requires type %s"
-							" but expression is of type %s",
-							format_type_be(typeneeded),
-							format_type_be(typesource)),
-					 errhint("You will need to rewrite or cast the expression."),
-					 parser_errposition(pstate, exprLocation(assignFrom))));
-		assignFrom = newFrom;
-	}
-
-	/*
 	 * Ready to build the SubscriptingRef node.
 	 */
 	sbsref = (SubscriptingRef *) makeNode(SubscriptingRef);
@@ -444,17 +354,30 @@ transformContainerSubscripts(ParseState *pstate,
 		sbsref->refassgnexpr = (Expr *) assignFrom;
 
 	sbsref->refcontainertype = containerType;
-	sbsref->refelemtype = elementType;
 	sbsref->reftypmod = containerTypMod;
 	/* refcollid will be set by parse_collate.c */
 	sbsref->refupperindexpr = upperIndexpr;
 	sbsref->reflowerindexpr = lowerIndexpr;
+	sbsref->refindexprslice = indexprSlice;
 	sbsref->refexpr = (Expr *) containerBase;
-	sbsref->refassgnexpr = (Expr *) assignFrom;
 
 	return sbsref;
 }
 
+SubscriptRoutines*
+getSubscriptingRoutines(Oid containerType)
+{
+	RegProcedure typsubshandler = get_typsubsprocs(containerType);
+
+	if (!OidIsValid(typsubshandler))
+		ereport(ERROR,
+				(errcode(ERRCODE_DATATYPE_MISMATCH),
+				 errmsg("cannot subscript type %s because it does not support subscripting",
+						format_type_be(containerType))));
+
+	return (SubscriptRoutines *) OidFunctionCall0(typsubshandler);
+}
+
 /*
  * make_const
  *
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 2901025..d8d665d 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -690,7 +690,7 @@ transformAssignmentIndirection(ParseState *pstate,
 							   Node *rhs,
 							   int location)
 {
-	Node	   *result;
+	Node	   *result = NULL;
 	List	   *subscripts = NIL;
 	bool		isSlice = false;
 	ListCell   *i;
@@ -853,27 +853,21 @@ transformAssignmentIndirection(ParseState *pstate,
 											 location);
 	}
 
-	/* base case: just coerce RHS to match target type ID */
-
-	result = coerce_to_target_type(pstate,
-								   rhs, exprType(rhs),
-								   targetTypeId, targetTypMod,
-								   COERCION_ASSIGNMENT,
-								   COERCE_IMPLICIT_CAST,
-								   -1);
-	if (result == NULL)
+	/*
+	 * Base case: just coerce RHS to match target type ID.
+	 * It's necessary only for field selection, since for
+	 * subscripting it's custom code who should define types.
+	 */
+	if (!targetIsSubscripting)
 	{
-		if (targetIsSubscripting)
-			ereport(ERROR,
-					(errcode(ERRCODE_DATATYPE_MISMATCH),
-					 errmsg("array assignment to \"%s\" requires type %s"
-							" but expression is of type %s",
-							targetName,
-							format_type_be(targetTypeId),
-							format_type_be(exprType(rhs))),
-					 errhint("You will need to rewrite or cast the expression."),
-					 parser_errposition(pstate, location)));
-		else
+		result = coerce_to_target_type(pstate,
+									   rhs, exprType(rhs),
+									   targetTypeId, targetTypMod,
+									   COERCION_ASSIGNMENT,
+									   COERCE_IMPLICIT_CAST,
+									   -1);
+
+		if (result == NULL)
 			ereport(ERROR,
 					(errcode(ERRCODE_DATATYPE_MISMATCH),
 					 errmsg("subfield \"%s\" is of type %s"
@@ -905,29 +899,42 @@ transformAssignmentSubscripts(ParseState *pstate,
 							  Node *rhs,
 							  int location)
 {
-	Node	   *result;
-	Oid			containerType;
-	int32		containerTypMod;
-	Oid			elementTypeId;
-	Oid			typeNeeded;
-	Oid			collationNeeded;
+	Node			  *result;
+	Oid				  containerType;
+	int32			  containerTypMod;
+	Oid				  collationNeeded;
+	SubscriptingRef   *sbsref;
+	SubscriptRoutines *sbsroutines;
 
 	Assert(subscripts != NIL);
 
 	/* Identify the actual array type and element type involved */
 	containerType = targetTypeId;
 	containerTypMod = targetTypMod;
-	elementTypeId = transformContainerType(&containerType, &containerTypMod);
 
-	/* Identify type that RHS must provide */
-	typeNeeded = isSlice ? containerType : elementTypeId;
+	/* process subscripts */
+	sbsref = transformContainerSubscripts(pstate,
+										  basenode,
+										  containerType,
+										  exprType(rhs),
+										  containerTypMod,
+										  subscripts,
+										  rhs);
+
+	sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype);
+
+	/*
+	 * Let custom code provide necessary information about required types:
+	 * refelemtype and refassgntype
+	 */
+	sbsref = sbsroutines->prepare(rhs != NULL, sbsref);
 
 	/*
 	 * container normally has same collation as elements, but there's an
 	 * exception: we might be subscripting a domain over a container type. In
 	 * that case use collation of the base type.
 	 */
-	if (containerType == targetTypeId)
+	if (sbsref->refcontainertype == containerType)
 		collationNeeded = targetCollation;
 	else
 		collationNeeded = get_typcollation(containerType);
@@ -937,25 +944,22 @@ transformAssignmentSubscripts(ParseState *pstate,
 										 NULL,
 										 targetName,
 										 true,
-										 typeNeeded,
-										 containerTypMod,
+										 sbsref->refassgntype,
+										 sbsref->reftypmod,
 										 collationNeeded,
 										 indirection,
 										 next_indirection,
 										 rhs,
 										 location);
 
-	/* process subscripts */
-	result = (Node *) transformContainerSubscripts(pstate,
-												   basenode,
-												   containerType,
-												   elementTypeId,
-												   containerTypMod,
-												   subscripts,
-												   rhs);
+	/* Provide fully prepared subscriptinng information for custom validation */
+	sbsref->refassgnexpr = (Expr *) rhs;
+	sbsroutines->validate(rhs != NULL, sbsref, pstate);
+
+	result = (Node *) sbsref;
 
 	/* If target was a domain over container, need to coerce up to the domain */
-	if (containerType != targetTypeId)
+	if (sbsref->refcontainertype != targetTypeId)
 	{
 		Oid			resulttype = exprType(result);
 
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 3e64390..981cdee 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -7913,17 +7913,18 @@ get_rule_expr(Node *node, deparse_context *context,
 				if (need_parens)
 					appendStringInfoChar(buf, ')');
 
-				/*
-				 * If there's a refassgnexpr, we want to print the node in the
-				 * format "container[subscripts] := refassgnexpr".  This is
-				 * not legal SQL, so decompilation of INSERT or UPDATE
-				 * statements should always use processIndirection as part of
-				 * the statement-level syntax.  We should only see this when
-				 * EXPLAIN tries to print the targetlist of a plan resulting
-				 * from such a statement.
-				 */
-				if (sbsref->refassgnexpr)
+				if (IsAssignment(sbsref))
 				{
+					/*
+					 * If there's a refassgnexpr, we want to print the node in the
+					 * format "container[subscripts] := refassgnexpr". This is not
+					 * legal SQL, so decompilation of INSERT or UPDATE statements
+					 * should always use processIndirection as part of the
+					 * statement-level syntax.  We should only see this when
+					 * EXPLAIN tries to print the targetlist of a plan resulting
+					 * from such a statement.
+					 */
+
 					Node	   *refassgnexpr;
 
 					/*
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 27602fa..2610c8d 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -3150,6 +3150,29 @@ get_range_subtype(Oid rangeOid)
 		return InvalidOid;
 }
 
+/*
+ * get_typsubshandler
+ *
+ *		Given the type OID, return the type's subscripting procedures, if any,
+ *		through pointers in arguments.
+ */
+RegProcedure
+get_typsubsprocs(Oid typid)
+{
+	HeapTuple		tp;
+
+	tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
+	if (HeapTupleIsValid(tp))
+	{
+		RegProcedure handler = ((Form_pg_type) GETSTRUCT(tp))->typsubshandler;
+		ReleaseSysCache(tp);
+
+		return handler;
+	}
+	else
+		return InvalidOid;
+}
+
 /*				---------- PG_INDEX CACHE ----------				 */
 
 /*
diff --git a/src/include/c.h b/src/include/c.h
index d752cc0..773f54c 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -532,6 +532,8 @@ typedef struct
 	int			indx[MAXDIM];
 }			IntArray;
 
+#define MAX_SUBSCRIPT_DEPTH 12
+
 /* ----------------
  *		Variable-length datatypes all share the 'struct varlena' header.
  *
diff --git a/src/include/catalog/pg_class.dat b/src/include/catalog/pg_class.dat
index 9bcf286..fe0aa57 100644
--- a/src/include/catalog/pg_class.dat
+++ b/src/include/catalog/pg_class.dat
@@ -24,7 +24,7 @@
   relname => 'pg_type', reltype => 'pg_type', relam => 'heap',
   relfilenode => '0', relpages => '0', reltuples => '0', relallvisible => '0',
   reltoastrelid => '0', relhasindex => 'f', relisshared => 'f',
-  relpersistence => 'p', relkind => 'r', relnatts => '31', relchecks => '0',
+  relpersistence => 'p', relkind => 'r', relnatts => '32', relchecks => '0',
   relhasrules => 'f', relhastriggers => 'f', relhassubclass => 'f',
   relrowsecurity => 'f', relforcerowsecurity => 'f', relispopulated => 't',
   relreplident => 'n', relispartition => 'f', relfrozenxid => '3',
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 2a584b4..d98bd05 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -217,6 +217,12 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati
 	 */
 	Oid			typcollation BKI_DEFAULT(0) BKI_LOOKUP(pg_collation);
 
+	/*
+	 * Type specific subscripting logic. If typsubshandler is none, it means
+	 * that this type doesn't support subscripting.
+	 */
+	regproc		typsubshandler BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
+
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 
 	/*
@@ -324,7 +330,8 @@ extern ObjectAddress TypeCreate(Oid newTypeOid,
 								int32 typeMod,
 								int32 typNDims,
 								bool typeNotNull,
-								Oid typeCollation);
+								Oid typeCollation,
+								Oid subscriptingParseProcedure);
 
 extern void GenerateTypeDependencies(Oid typeObjectId,
 									 Form_pg_type typeForm,
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index d21dbead..f9cf0af 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -19,7 +19,7 @@
 
 /* forward references to avoid circularity */
 struct ExprEvalStep;
-struct SubscriptingRefState;
+struct SubscriptRoutines;
 
 /* Bits in ExprState->flags (see also execnodes.h for public flag bits): */
 /* expression's interpreter has been initialized */
@@ -672,13 +672,13 @@ typedef struct SubscriptingRefState
 	/* numupper and upperprovided[] are filled at compile time */
 	/* at runtime, extracted subscript datums get stored in upperindex[] */
 	int			numupper;
-	bool		upperprovided[MAXDIM];
-	int			upperindex[MAXDIM];
+	bool		upperprovided[MAX_SUBSCRIPT_DEPTH];
+	Datum		upperindex[MAX_SUBSCRIPT_DEPTH];
 
 	/* similarly for lower indexes, if any */
 	int			numlower;
-	bool		lowerprovided[MAXDIM];
-	int			lowerindex[MAXDIM];
+	bool		lowerprovided[MAX_SUBSCRIPT_DEPTH];
+	Datum		lowerindex[MAX_SUBSCRIPT_DEPTH];
 
 	/* subscript expressions get evaluated into here */
 	Datum		subscriptvalue;
@@ -691,6 +691,9 @@ typedef struct SubscriptingRefState
 	/* if we have a nested assignment, SBSREF_OLD puts old value here */
 	Datum		prevvalue;
 	bool		prevnull;
+
+	bool		resnull;
+	struct SubscriptRoutines *sbsroutines;
 } SubscriptingRefState;
 
 
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 860a84d..e7db3b2 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -403,13 +403,17 @@ typedef struct SubscriptingRef
 	Expr		xpr;
 	Oid			refcontainertype;	/* type of the container proper */
 	Oid			refelemtype;	/* type of the container elements */
+	Oid			refassgntype;		/* type of assignment expr that is required */
 	int32		reftypmod;		/* typmod of the container (and elements too) */
 	Oid			refcollid;		/* OID of collation, or InvalidOid if none */
+	Oid			refnestedfunc;		/* OID of type-specific function to handle nested assignment */
 	List	   *refupperindexpr;	/* expressions that evaluate to upper
 									 * container indexes */
 	List	   *reflowerindexpr;	/* expressions that evaluate to lower
 									 * container indexes, or NIL for single
 									 * container element */
+	List       *refindexprslice;    /* whether or not related indexpr from
+									 * reflowerindexpr is a slice */
 	Expr	   *refexpr;		/* the expression that evaluates to a
 								 * container value */
 
@@ -417,6 +421,8 @@ typedef struct SubscriptingRef
 								 * fetch */
 } SubscriptingRef;
 
+#define IsAssignment(expr) ( ((SubscriptingRef*) expr)->refassgnexpr != NULL )
+
 /*
  * CoercionContext - distinguishes the allowed set of type casts
  *
diff --git a/src/include/nodes/subscripting.h b/src/include/nodes/subscripting.h
new file mode 100644
index 0000000..1800d5e
--- /dev/null
+++ b/src/include/nodes/subscripting.h
@@ -0,0 +1,42 @@
+/*-------------------------------------------------------------------------
+ *
+ * subscripting.h
+ *		API for generic type subscripting
+ *
+ * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/nodes/subscripting.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SUBSCRIPTING_H
+#define SUBSCRIPTING_H
+
+#include "parser/parse_node.h"
+#include "nodes/primnodes.h"
+
+struct ParseState;
+struct SubscriptingRefState;
+
+/* Callback function signatures --- see xsubscripting.sgml for more info. */
+typedef SubscriptingRef * (*SubscriptingPrepare) (bool isAssignment, SubscriptingRef *sbsef);
+
+typedef SubscriptingRef * (*SubscriptingValidate) (bool isAssignment, SubscriptingRef *sbsef,
+												   struct ParseState *pstate);
+
+typedef Datum (*SubscriptingFetch) (Datum source, struct SubscriptingRefState *sbsrefstate);
+
+typedef Datum (*SubscriptingAssign) (Datum source, struct SubscriptingRefState *sbrsefstate);
+
+typedef struct SubscriptRoutines
+{
+	SubscriptingPrepare		prepare;
+	SubscriptingValidate	validate;
+	SubscriptingFetch		fetch;
+	SubscriptingAssign		assign;
+
+} SubscriptRoutines;
+
+
+#endif							/* SUBSCRIPTING_H */
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 7c099e7..28f7d27 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -15,6 +15,7 @@
 #define PARSE_NODE_H
 
 #include "nodes/parsenodes.h"
+#include "nodes/subscripting.h"
 #include "utils/queryenvironment.h"
 #include "utils/relcache.h"
 
@@ -274,7 +275,7 @@ extern void cancel_parser_errposition_callback(ParseCallbackState *pcbstate);
 
 extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno,
 					 int location);
-extern Oid	transformContainerType(Oid *containerType, int32 *containerTypmod);
+extern void	transformContainerType(Oid *containerType, int32 *containerTypmod);
 
 extern SubscriptingRef *transformContainerSubscripts(ParseState *pstate,
 													 Node *containerBase,
@@ -283,6 +284,7 @@ extern SubscriptingRef *transformContainerSubscripts(ParseState *pstate,
 													 int32 containerTypMod,
 													 List *indirection,
 													 Node *assignFrom);
+extern SubscriptRoutines* getSubscriptingRoutines(Oid containerType);
 extern Const *make_const(ParseState *pstate, Value *value, int location);
 
 #endif							/* PARSE_NODE_H */
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index c8df5bf..d7f250a 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -179,6 +179,7 @@ extern void free_attstatsslot(AttStatsSlot *sslot);
 extern char *get_namespace_name(Oid nspid);
 extern char *get_namespace_name_or_temp(Oid nspid);
 extern Oid	get_range_subtype(Oid rangeOid);
+extern RegProcedure get_typsubsprocs(Oid typid);
 extern Oid	get_index_column_opclass(Oid index_oid, int attno);
 
 #define type_is_array(typid)  (get_element_type(typid) != InvalidOid)
-- 
2.7.4


--------------3C456A3C89C0AEF059999FAB
Content-Type: text/x-patch;
 name="v28-0002-Subscripting-for-array.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="v28-0002-Subscripting-for-array.patch"



^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* Some shared memory chunks are allocated even if related processes won't start
@ 2024-03-04 05:26  Hayato Kuroda (Fujitsu) <[email protected]>
  0 siblings, 2 replies; 2399+ messages in thread

From: Hayato Kuroda (Fujitsu) @ 2024-03-04 05:26 UTC (permalink / raw)
  To: '[email protected]' <[email protected]>

Dear hackers,

While reading codes, I found that ApplyLauncherShmemInit() and AutoVacuumShmemInit()
are always called even if they would not be launched.
It may be able to reduce the start time to avoid the unnecessary allocation.
However, I know this improvement would be quite small because the allocated chunks are
quite small.

Anyway, there are several ways to fix:

1)
Skip calling ShmemInitStruct() if the related process would not be launched.
I think this approach is the easiest way. E.g.,

```
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -962,6 +962,9 @@ ApplyLauncherShmemInit(void)
 {
     bool        found;

+    if (max_logical_replication_workers == 0 || IsBinaryUpgrade)
+        return;
+
```

2)
Dynamically allocate the shared memory. This was allowed by recent commit [1].
I made a small PoC only for logical launcher to show what I meant. PSA diff file.
Since some processes (backend, apply worker, parallel apply worker, and tablesync worker)
refers the chunk, codes for attachment must be added on the several places.

If you agree it should be fixed, I will create a patch. Thought?

[1]: https://github.com/postgres/postgres/commit/8b2bcf3f287c79eaebf724cba57e5ff664b01e06

Best Regards,
Hayato Kuroda
FUJITSU LIMITED
https://www.fujitsu.com/ 



Attachments:

  [application/octet-stream] dynamic_allocation.diff (84B, ../../TYCPR01MB12077BFDFBC142086D424FDFEF5232@TYCPR01MB12077.jpnprd01.prod.outlook.com/2-dynamic_allocation.diff)
  download | inline diff:
53	22	src/backend/replication/logical/launcher.c
0	1	src/backend/storage/ipc/ipci.c


^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* Re: Some shared memory chunks are allocated even if related processes won't start
@ 2024-03-04 05:33  Tom Lane <[email protected]>
  parent: Hayato Kuroda (Fujitsu) <[email protected]>
  1 sibling, 1 reply; 2399+ messages in thread

From: Tom Lane @ 2024-03-04 05:33 UTC (permalink / raw)
  To: Hayato Kuroda (Fujitsu) <[email protected]>; +Cc: '[email protected]' <[email protected]>

"Hayato Kuroda (Fujitsu)" <[email protected]> writes:
> While reading codes, I found that ApplyLauncherShmemInit() and AutoVacuumShmemInit()
> are always called even if they would not be launched.
> It may be able to reduce the start time to avoid the unnecessary allocation.

Why would this be a good idea?  It would require preventing the
decision not to launch them from being changed later, except via
postmaster restart.  We've generally been trying to move away
from unchangeable-without-restart decisions.  In your example,

> +    if (max_logical_replication_workers == 0 || IsBinaryUpgrade)
> +        return;

max_logical_replication_workers is already PGC_POSTMASTER so there's
not any immediate loss of flexibility, but I don't think it's a great
idea to introduce another reason why it has to be PGC_POSTMASTER.

			regards, tom lane





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* RE: Some shared memory chunks are allocated even if related processes won't start
@ 2024-03-04 06:10  Hayato Kuroda (Fujitsu) <[email protected]>
  parent: Tom Lane <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Hayato Kuroda (Fujitsu) @ 2024-03-04 06:10 UTC (permalink / raw)
  To: 'Tom Lane' <[email protected]>; +Cc: '[email protected]' <[email protected]>

Dear Tom,

Thanks for replying!

> "Hayato Kuroda (Fujitsu)" <[email protected]> writes:
> > While reading codes, I found that ApplyLauncherShmemInit() and
> AutoVacuumShmemInit()
> > are always called even if they would not be launched.
> > It may be able to reduce the start time to avoid the unnecessary allocation.
> 
> Why would this be a good idea?  It would require preventing the
> decision not to launch them from being changed later, except via
> postmaster restart.

Right. It is important to relax their GucContext.

> We've generally been trying to move away
> from unchangeable-without-restart decisions.  In your example,
> 
> > +    if (max_logical_replication_workers == 0 || IsBinaryUpgrade)
> > +        return;
> 
> max_logical_replication_workers is already PGC_POSTMASTER so there's
> not any immediate loss of flexibility, but I don't think it's a great
> idea to introduce another reason why it has to be PGC_POSTMASTER.

You are right. The first example implied the max_logical_replication_workers
won't be changed. So it is not appropriate.
So ... what about second one? The approach allows to allocate a memory after
startup, which means that users may able to change the parameter from 0 to
natural number in future. (Of course, such an operation is prohibit for now).
Can it be an initial step to ease the condition?

Best Regards,
Hayato Kuroda
FUJITSU LIMITED
https://www.fujitsu.com/






^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* Re: Some shared memory chunks are allocated even if related processes won't start
@ 2024-03-04 08:09  Alvaro Herrera <[email protected]>
  parent: Hayato Kuroda (Fujitsu) <[email protected]>
  1 sibling, 1 reply; 2399+ messages in thread

From: Alvaro Herrera @ 2024-03-04 08:09 UTC (permalink / raw)
  To: Hayato Kuroda (Fujitsu) <[email protected]>; +Cc: '[email protected]' <[email protected]>

On 2024-Mar-04, Hayato Kuroda (Fujitsu) wrote:

> Dear hackers,
> 
> While reading codes, I found that ApplyLauncherShmemInit() and
> AutoVacuumShmemInit() are always called even if they would not be
> launched.

Note that there are situations where the autovacuum launcher is started
even though autovacuum is nominally turned off, and I suspect your
proposal would break that.  IIRC this occurs when the Xid or multixact
counters cross the max_freeze_age threshold.

-- 
Álvaro Herrera         PostgreSQL Developer  —  https://www.EnterpriseDB.com/
"Porque Kim no hacía nada, pero, eso sí,
con extraordinario éxito" ("Kim", Kipling)





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* RE: Some shared memory chunks are allocated even if related processes won't start
@ 2024-03-04 09:50  Hayato Kuroda (Fujitsu) <[email protected]>
  parent: Alvaro Herrera <[email protected]>
  0 siblings, 1 reply; 2399+ messages in thread

From: Hayato Kuroda (Fujitsu) @ 2024-03-04 09:50 UTC (permalink / raw)
  To: 'Alvaro Herrera' <[email protected]>; +Cc: '[email protected]' <[email protected]>

Dear Alvaro,

Thanks for giving comments!

> > While reading codes, I found that ApplyLauncherShmemInit() and
> > AutoVacuumShmemInit() are always called even if they would not be
> > launched.
> 
> Note that there are situations where the autovacuum launcher is started
> even though autovacuum is nominally turned off, and I suspect your
> proposal would break that.  IIRC this occurs when the Xid or multixact
> counters cross the max_freeze_age threshold.

Right. In GetNewTransactionId(), SetTransactionIdLimit() and some other places,
PMSIGNAL_START_AUTOVAC_LAUNCHER is sent to postmaster when the xid exceeds
autovacuum_freeze_max_age. This work has already been written in the doc [1]:

```
To ensure that this does not happen, autovacuum is invoked on any table that
might contain unfrozen rows with XIDs older than the age specified by the
configuration parameter autovacuum_freeze_max_age. (This will happen even
if autovacuum is disabled.)
```

This means that my first idea won't work well. Even if the postmaster does not
initially allocate shared memory, backends may request to start auto vacuum and
use the region. However, the second idea is still valid, which allows the allocation
of shared memory dynamically. This is a bit efficient for the system which tuples
won't be frozen. Thought?

[1]: https://www.postgresql.org/docs/devel/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND

Best Regards,
Hayato Kuroda
FUJITSU LIMITED
https://www.fujitsu.com/ 



^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* Re: Some shared memory chunks are allocated even if related processes won't start
@ 2024-03-04 11:52  'Alvaro Herrera' <[email protected]>
  parent: Hayato Kuroda (Fujitsu) <[email protected]>
  0 siblings, 1 reply; 2399+ messages in thread

From: 'Alvaro Herrera' @ 2024-03-04 11:52 UTC (permalink / raw)
  To: Hayato Kuroda (Fujitsu) <[email protected]>; +Cc: '[email protected]' <[email protected]>

On 2024-Mar-04, Hayato Kuroda (Fujitsu) wrote:

> However, the second idea is still valid, which allows the allocation
> of shared memory dynamically. This is a bit efficient for the system
> which tuples won't be frozen. Thought?

I think it would be worth allocating AutoVacuumShmem->av_workItems using
dynamic shmem allocation, particularly to prevent workitems from being
discarded just because the array is full¹; but other than that, the
struct is just 64 bytes long so I doubt it's useful to allocate it
dynamically.

¹ I mean, if the array is full, just allocate another array, point to it
from the original one, and keep going.

-- 
Álvaro Herrera         PostgreSQL Developer  —  https://www.EnterpriseDB.com/
"The problem with the facetime model is not just that it's demoralizing, but
that the people pretending to work interrupt the ones actually working."
                  -- Paul Graham, http://www.paulgraham.com/opensource.html





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* RE: Some shared memory chunks are allocated even if related processes won't start
@ 2024-03-04 13:11  Hayato Kuroda (Fujitsu) <[email protected]>
  parent: 'Alvaro Herrera' <[email protected]>
  0 siblings, 1 reply; 2399+ messages in thread

From: Hayato Kuroda (Fujitsu) @ 2024-03-04 13:11 UTC (permalink / raw)
  To: 'Alvaro Herrera' <[email protected]>; +Cc: '[email protected]' <[email protected]>

Dear Alvaro,

Thanks for discussing!

> 
> I think it would be worth allocating AutoVacuumShmem->av_workItems using
> dynamic shmem allocation, particularly to prevent workitems from being
> discarded just because the array is full¹; but other than that, the
> struct is just 64 bytes long so I doubt it's useful to allocate it
> dynamically.
> 
> ¹ I mean, if the array is full, just allocate another array, point to it
> from the original one, and keep going.

OK, I understood that my initial proposal is not so valuable, so I can withdraw it.

About the suggetion, you imagined AutoVacuumRequestWork() and brininsert(),
right? I agreed it sounds good, but I don't think it can be implemented by current
interface. An interface for dynamically allocating memory is GetNamedDSMSegment(),
and it returns the same shared memory region if input names are the same.
Therefore, there is no way to re-alloc the shared memory.

Best Regards,
Hayato Kuroda
FUJITSU LIMITED
https://www.fujitsu.com/ 



^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* Re: Some shared memory chunks are allocated even if related processes won't start
@ 2024-03-04 13:50  'Alvaro Herrera' <[email protected]>
  parent: Hayato Kuroda (Fujitsu) <[email protected]>
  0 siblings, 1 reply; 2399+ messages in thread

From: 'Alvaro Herrera' @ 2024-03-04 13:50 UTC (permalink / raw)
  To: Hayato Kuroda (Fujitsu) <[email protected]>; +Cc: '[email protected]' <[email protected]>

Hello Hayato,

On 2024-Mar-04, Hayato Kuroda (Fujitsu) wrote:

> OK, I understood that my initial proposal is not so valuable, so I can
> withdraw it.

Yeah, that's what it seems to me.

> About the suggetion, you imagined AutoVacuumRequestWork() and
> brininsert(), right?

Correct.

> I agreed it sounds good, but I don't think it can be implemented by
> current interface. An interface for dynamically allocating memory is
> GetNamedDSMSegment(), and it returns the same shared memory region if
> input names are the same.  Therefore, there is no way to re-alloc the
> shared memory.

Yeah, I was imagining something like this: the workitem-array becomes a
struct, which has a name and a "next" pointer and a variable number of
workitem slots; the AutoVacuumShmem struct has a pointer to the first
workitem-struct and the last one; when a workitem is requested by
brininsert, we initially allocate via GetNamedDSMSegment("workitem-0") a
workitem-struct with a smallish number of elements; if we request
another workitem and the array is full, we allocate another array via
GetNamedDSMSegment("workitem-1") and store a pointer to it in workitem-0
(so that the list can be followed by an autovacuum worker that's
processing the database), and it's also set as the tail of the list in
AutoVacuumShmem (so that we know where to store further work items).
When all items in a workitem-struct are processed, we can free it
(I guess via dsm_unpin_segment), and make AutoVacuumShmem->av_workitems
point to the next one in the list.

This way, the "array" can grow arbitrarily.

-- 
Álvaro Herrera         PostgreSQL Developer  —  https://www.EnterpriseDB.com/





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* RE: Some shared memory chunks are allocated even if related processes won't start
@ 2024-03-05 02:00  Hayato Kuroda (Fujitsu) <[email protected]>
  parent: 'Alvaro Herrera' <[email protected]>
  0 siblings, 1 reply; 2399+ messages in thread

From: Hayato Kuroda (Fujitsu) @ 2024-03-05 02:00 UTC (permalink / raw)
  To: 'Alvaro Herrera' <[email protected]>; +Cc: '[email protected]' <[email protected]>

Dear Alvaro,

Thanks for giving comments!

> > I agreed it sounds good, but I don't think it can be implemented by
> > current interface. An interface for dynamically allocating memory is
> > GetNamedDSMSegment(), and it returns the same shared memory region if
> > input names are the same.  Therefore, there is no way to re-alloc the
> > shared memory.
> 
> Yeah, I was imagining something like this: the workitem-array becomes a
> struct, which has a name and a "next" pointer and a variable number of
> workitem slots; the AutoVacuumShmem struct has a pointer to the first
> workitem-struct and the last one; when a workitem is requested by
> brininsert, we initially allocate via GetNamedDSMSegment("workitem-0") a
> workitem-struct with a smallish number of elements; if we request
> another workitem and the array is full, we allocate another array via
> GetNamedDSMSegment("workitem-1") and store a pointer to it in workitem-0
> (so that the list can be followed by an autovacuum worker that's
> processing the database), and it's also set as the tail of the list in
> AutoVacuumShmem (so that we know where to store further work items).
> When all items in a workitem-struct are processed, we can free it
> (I guess via dsm_unpin_segment), and make AutoVacuumShmem->av_workitems
> point to the next one in the list.
> 
> This way, the "array" can grow arbitrarily.
>

Basically sounds good. My concerns are:

* GetNamedDSMSegment() does not returns a raw pointer to dsm_segment. This means
  that it may be difficult to do dsm_unpin_segment on the caller side.
* dynamic shared memory is recorded in dhash (dsm_registry_table) and the entry
  won't be deleted. The reference for the chunk might be remained.

Overall, it may be needed that dsm_registry may be also extended. I do not start
working yet, so will share results after trying them.

Best Regards,
Hayato Kuroda
FUJITSU LIMITED
https://www.fujitsu.com/ 



^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* Re: Some shared memory chunks are allocated even if related processes won't start
@ 2024-03-05 07:34  'Alvaro Herrera' <[email protected]>
  parent: Hayato Kuroda (Fujitsu) <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: 'Alvaro Herrera' @ 2024-03-05 07:34 UTC (permalink / raw)
  To: Hayato Kuroda (Fujitsu) <[email protected]>; +Cc: [email protected]

On 2024-Mar-05, Hayato Kuroda (Fujitsu) wrote:

> Basically sounds good. My concerns are:
> 
> * GetNamedDSMSegment() does not returns a raw pointer to dsm_segment. This means
>   that it may be difficult to do dsm_unpin_segment on the caller side.

Maybe we don't need a "named" DSM segment at all, and instead just use
bare dsm segments (dsm_create and friends) or a DSA -- not sure.  But
see commit 31ae1638ce35, which removed use of a DSA in autovacuum/BRIN.
Maybe fixing this is just a matter of reverting that commit.  At the
time, there was a belief that DSA wasn't supported everywhere so we
couldn't use it for autovacuum workitem stuff, but I think our reliance
on DSA is now past the critical point.

BTW, we should turn BRIN autosummarization to be on by default.

-- 
Álvaro Herrera         PostgreSQL Developer  —  https://www.EnterpriseDB.com/
"Las mujeres son como hondas:  mientras más resistencia tienen,
 más lejos puedes llegar con ellas"  (Jonas Nightingale, Leap of Faith)





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-22 15:01  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw)

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 protected]>
---
 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--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types via the
zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address().

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c          | 93 ++++++++++++++++++++
 src/test/regress/expected/event_trigger.out  | 17 ++++
 src/test/regress/expected/object_address.out |  4 +
 src/test/regress/sql/event_trigger.sql       | 13 +++
 src/test/regress/sql/object_address.sql      |  2 +
 5 files changed, 129 insertions(+)
  62.4% src/backend/catalog/
  25.6% src/test/regress/expected/
  11.8% 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/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..729c3537f25 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..620dacf1045 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--gtUR827Uq8d5gVsQ--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread

* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error
@ 2026-04-23 09:27  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 2399+ messages in thread

From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw)

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

During DROP PROPERTY GRAPH, this manifests when an event trigger is active,
because pg_event_trigger_ddl_commands() calls these functions. The same code
paths are also reachable via pg_identify_object() and pg_identify_object_as_address().

This commit adds the missing cases.

Test coverage is added in object_address.sql for these two catalog types and
in create_property_graph.sql covering all property graph object types.

A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly
when an event trigger is active.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg
---
 src/backend/catalog/objectaddress.c           | 93 +++++++++++++++++++
 .../expected/create_property_graph.out        | 78 ++++++++++++++++
 src/test/regress/expected/event_trigger.out   | 17 ++++
 src/test/regress/expected/object_address.out  | 10 +-
 .../regress/sql/create_property_graph.sql     | 23 +++++
 src/test/regress/sql/event_trigger.sql        | 13 +++
 src/test/regress/sql/object_address.sql       |  6 +-
 7 files changed, 238 insertions(+), 2 deletions(-)
  14.7% src/backend/catalog/
  75.5% src/test/regress/expected/
   9.7% 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..eb9e17fb727 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
  type                    | create_property_graph_tests | g2   | create_property_graph_tests.g2
 (21 rows)
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+                           obj                            |                                   ident                                    |                                    addr                                    
+----------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ edge e of property graph gt                              | ("property graph element",,,"e of create_property_graph_tests.gt")         | ("property graph element","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of edge e of property graph gt                   | ("property graph element label",,,"e of create_property_graph_tests.gt")   | ("property graph element label","{create_property_graph_tests,gt,e}",{})
+ label e of property graph gt                             | ("property graph label",,,"e of create_property_graph_tests.gt")           | ("property graph label","{create_property_graph_tests,gt,e}",{})
+ label v1 of property graph gt                            | ("property graph label",,,"v1 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v1 of vertex v1 of property graph gt               | ("property graph element label",,,"v1 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v1}",{})
+ label v2 of property graph gt                            | ("property graph label",,,"v2 of create_property_graph_tests.gt")          | ("property graph label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ label v2 of vertex v2 of property graph gt               | ("property graph element label",,,"v2 of create_property_graph_tests.gt")  | ("property graph element label","{create_property_graph_tests,gt,v2}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property a of property graph gt                          | ("property graph property",,,"a of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,a}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{})
+ property b of property graph gt                          | ("property graph property",,,"b of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,b}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of label e of edge e of property graph gt     | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property c of property graph gt                          | ("property graph property",,,"c of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,c}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k1 of property graph gt                         | ("property graph property",,,"k1 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k1}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of label e of edge e of property graph gt    | ("property graph label property",,,"e of create_property_graph_tests.gt")  | ("property graph label property","{create_property_graph_tests,gt,e}",{})
+ property k2 of property graph gt                         | ("property graph property",,,"k2 of create_property_graph_tests.gt")       | ("property graph property","{create_property_graph_tests,gt,k2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property m of property graph gt                          | ("property graph property",,,"m of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,m}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{})
+ property n of property graph gt                          | ("property graph property",,,"n of create_property_graph_tests.gt")        | ("property graph property","{create_property_graph_tests,gt,n}",{})
+ type gt                                                  | (type,create_property_graph_tests,gt,create_property_graph_tests.gt)       | (type,{create_property_graph_tests.gt},{})
+ type gt[]                                                | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[])    | (type,{create_property_graph_tests.gt[]},{})
+ vertex v1 of property graph gt                           | ("property graph element",,,"v1 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v1}",{})
+ vertex v2 of property graph gt                           | ("property graph element",,,"v2 of create_property_graph_tests.gt")        | ("property graph element","{create_property_graph_tests,gt,v2}",{})
+(52 rows)
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 CREATE PROPERTY GRAPH create_property_graph_tests.g2
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 065f586310f..ed8d5df397e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -173,6 +173,23 @@ NOTICE:  test_event_trigger: ddl_command_end CREATE USER MAPPING
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 NOTICE:  test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+NOTICE:  test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
+DROP PROPERTY GRAPH gx;
+NOTICE:  test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
+DROP TABLE t1x, t2x;
+NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 97227d67a54..5e53f0b092e 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -84,7 +86,9 @@ WARNING:  error for toast table column: unsupported object type "toast table col
 WARNING:  error for view column: unsupported object type "view column"
 WARNING:  error for materialized view column: unsupported object type "materialized view column"
 WARNING:  error for property graph element: unsupported object type "property graph element"
+WARNING:  error for property graph element label: unrecognized object type "property graph element label"
 WARNING:  error for property graph label: unsupported object type "property graph label"
+WARNING:  error for property graph label property: unrecognized object type "property graph label property"
 WARNING:  error for property graph property: unsupported object type "property graph property"
 -- miscellaneous other errors
 select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
@@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
@@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
 ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
 ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
 ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
+("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
 ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
+("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
 -- restore normal output mode
 \a\t
diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql
index 241f93df302..9608dd5c4af 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).*
           refobjid = 'create_property_graph_tests.g2'::regclass
     ORDER BY 1, 2, 3, 4;
 
+-- test object address functions with recursive dependency walk
+-- covers all property graph object types including indirect dependents
+SELECT *
+FROM (
+    WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
+        SELECT classid, objid, objsubid,
+               refclassid, refobjid, refobjsubid
+        FROM pg_depend
+        WHERE refclassid = 'pg_class'::regclass AND
+              refobjid = 'create_property_graph_tests.gt'::regclass
+        UNION ALL
+        SELECT d.classid, d.objid, d.objsubid,
+               d.refclassid, d.refobjid, d.refobjsubid
+        FROM pg_depend d
+        JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
+    )
+    SELECT pg_describe_object(classid, objid, objsubid) as obj,
+           pg_identify_object(classid, objid, objsubid) as ident,
+           pg_identify_object_as_address(classid, objid, objsubid) as addr
+    FROM deps
+) s
+ORDER BY obj COLLATE "C", ident::text COLLATE "C";
+
 \a\t
 SELECT pg_get_propgraphdef('g2'::regclass);
 SELECT pg_get_propgraphdef('g3'::regclass);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 32e9bb58c5e..271f443378b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server;
 alter default privileges for role regress_evt_user
  revoke delete on tables from regress_evt_user;
 
+-- DROP PROPERTY GRAPH should work with event trigger in place
+CREATE TABLE t1x (a int PRIMARY KEY, b text);
+CREATE TABLE t2x (i int PRIMARY KEY, j text);
+
+CREATE PROPERTY GRAPH gx
+	VERTEX TABLES (
+		t1x KEY (a) LABEL l1 PROPERTIES (b AS p1),
+		t2x KEY (i) LABEL l2 PROPERTIES (j AS p1)
+);
+
+DROP PROPERTY GRAPH gx;
+DROP TABLE t1x, t2x;
+
 -- alter owner to non-superuser should fail
 alter event trigger regress_event_trigger owner to regress_evt_user;
 
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index 1bbe9457c1c..27109d421c7 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -67,7 +67,9 @@ DECLARE
 BEGIN
     FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
         ('toast table column'), ('view column'), ('materialized view column'),
-        ('property graph element'), ('property graph label'), ('property graph property')
+        ('property graph element'), ('property graph element label'),
+        ('property graph label'), ('property graph label property'),
+        ('property graph property')
     LOOP
         BEGIN
             PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES
     ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL
     ('pg_policy'::regclass, 0, 0), -- no policy
     ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
+    ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
     ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
+    ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
     ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
     ('pg_publication'::regclass, 0, 0), -- no publication
     ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
-- 
2.34.1


--R84XrR4Hgw0dH3Ec--





^ permalink  raw  reply  [nested|flat] 2399+ messages in thread


end of thread, other threads:[~2026-04-23 09:27 UTC | newest]

Thread overview: 2399+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2019-01-31 21:37 [PATCH v28 1/5] Base implementation of subscripting mechanism erthalion <[email protected]>
2024-03-04 05:26 Some shared memory chunks are allocated even if related processes won't start Hayato Kuroda (Fujitsu) <[email protected]>
2024-03-04 05:33 ` Re: Some shared memory chunks are allocated even if related processes won't start Tom Lane <[email protected]>
2024-03-04 06:10   ` RE: Some shared memory chunks are allocated even if related processes won't start Hayato Kuroda (Fujitsu) <[email protected]>
2024-03-04 08:09 ` Re: Some shared memory chunks are allocated even if related processes won't start Alvaro Herrera <[email protected]>
2024-03-04 09:50   ` RE: Some shared memory chunks are allocated even if related processes won't start Hayato Kuroda (Fujitsu) <[email protected]>
2024-03-04 11:52     ` Re: Some shared memory chunks are allocated even if related processes won't start 'Alvaro Herrera' <[email protected]>
2024-03-04 13:11       ` RE: Some shared memory chunks are allocated even if related processes won't start Hayato Kuroda (Fujitsu) <[email protected]>
2024-03-04 13:50         ` Re: Some shared memory chunks are allocated even if related processes won't start 'Alvaro Herrera' <[email protected]>
2024-03-05 02:00           ` RE: Some shared memory chunks are allocated even if related processes won't start Hayato Kuroda (Fujitsu) <[email protected]>
2024-03-05 07:34             ` Re: Some shared memory chunks are allocated even if related processes won't start 'Alvaro Herrera' <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>
2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]>

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